forked from mirror/openmw-tes3mp
Merge
This commit is contained in:
commit
51fb9e67cd
517 changed files with 26376 additions and 36646 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -7,3 +7,9 @@ Docs/mainpage.hpp
|
|||
CMakeFiles
|
||||
*/CMakeFiles
|
||||
CMakeCache.txt
|
||||
moc_*.cxx
|
||||
cmake_install.cmake
|
||||
*.[ao]
|
||||
Makefile
|
||||
makefile
|
||||
data
|
||||
|
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,6 +0,0 @@
|
|||
[submodule "libs/mangle"]
|
||||
path = libs/mangle
|
||||
url = git://github.com/zinnschlag/mangle.git
|
||||
[submodule "libs/openengine"]
|
||||
path = libs/openengine
|
||||
url = git://github.com/zinnschlag/OpenEngine
|
266
CMakeLists.txt
266
CMakeLists.txt
|
@ -1,11 +1,13 @@
|
|||
project(OpenMW)
|
||||
|
||||
IF (APPLE)
|
||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/OpenMW.app")
|
||||
if (APPLE)
|
||||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||
|
||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||
|
||||
# using 10.6 sdk
|
||||
set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk")
|
||||
ENDIF (APPLE)
|
||||
endif (APPLE)
|
||||
|
||||
# Macros
|
||||
|
||||
|
@ -16,8 +18,8 @@ include (OpenMWMacros)
|
|||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 11)
|
||||
set (OPENMW_VERSION_RELEASE 1)
|
||||
set (OPENMW_VERSION_MINOR 13)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
||||
|
@ -25,6 +27,8 @@ set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VE
|
|||
|
||||
configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp")
|
||||
|
||||
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
|
||||
|
||||
# Sound source selection
|
||||
option(USE_AUDIERE "use Audiere for sound" OFF)
|
||||
option(USE_FFMPEG "use ffmpeg for sound" OFF)
|
||||
|
@ -94,6 +98,7 @@ source_group(libs\\mangle FILES ${MANGLE_ALL})
|
|||
set(OENGINE_OGRE
|
||||
${LIBDIR}/openengine/ogre/renderer.cpp
|
||||
${LIBDIR}/openengine/ogre/mouselook.cpp
|
||||
${LIBDIR}/openengine/ogre/fader.cpp
|
||||
)
|
||||
set(OENGINE_GUI
|
||||
${LIBDIR}/openengine/gui/events.cpp
|
||||
|
@ -186,11 +191,18 @@ find_package(Boost REQUIRED COMPONENTS system filesystem program_options thread)
|
|||
find_package(OIS REQUIRED)
|
||||
find_package(OpenAL REQUIRED)
|
||||
find_package(Bullet REQUIRED)
|
||||
IF(OGRE_STATIC)
|
||||
find_package(Cg REQUIRED)
|
||||
IF(WIN32)
|
||||
set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_Direct3D9_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS})
|
||||
ELSE(WIN32)
|
||||
set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS})
|
||||
ENDIF(WIN32)
|
||||
ENDIF(OGRE_STATIC)
|
||||
include_directories("."
|
||||
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE
|
||||
${OIS_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
|
||||
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
|
||||
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
|
||||
${PLATFORM_INCLUDE_DIR}
|
||||
${CMAKE_HOME_DIRECTORY}/extern/caelum/include
|
||||
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include
|
||||
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/OgrePlatform/include
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
|
@ -200,7 +212,14 @@ include_directories("."
|
|||
|
||||
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
|
||||
|
||||
add_subdirectory( extern/caelum )
|
||||
if(APPLE)
|
||||
# List used Ogre plugins
|
||||
SET(USED_OGRE_PLUGINS "RenderSystem_GL"
|
||||
"Plugin_OctreeSceneManager"
|
||||
"Plugin_CgProgramManager"
|
||||
"Plugin_ParticleFX")
|
||||
endif(APPLE)
|
||||
|
||||
add_subdirectory( extern/mygui_3.0.1 )
|
||||
add_subdirectory( files/)
|
||||
|
||||
|
@ -211,9 +230,6 @@ add_subdirectory( files/)
|
|||
# MyGUI: extern/mygui_3.0.0/
|
||||
add_definitions(-DMYGUI_STATIC)
|
||||
|
||||
# Caelum: extern/caelum/
|
||||
add_definitions(-DCAELUM_STATIC)
|
||||
|
||||
# Specify build paths
|
||||
|
||||
if (APPLE)
|
||||
|
@ -244,61 +260,32 @@ if (APPLE)
|
|||
"${OpenMW_BINARY_DIR}/plugins.cfg")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
|
||||
"${APP_BUNDLE_DIR}/Contents/Info.plist" COPYONLY)
|
||||
"${APP_BUNDLE_DIR}/Contents/Info.plist")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns
|
||||
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
||||
|
||||
|
||||
# prepare plugins
|
||||
configure_file(${OGRE_PLUGIN_DIR}/RenderSystem_GL.dylib
|
||||
"${APP_BUNDLE_DIR}/Contents/Plugins/RenderSystem_GL.dylib" COPYONLY)
|
||||
|
||||
configure_file(${OGRE_PLUGIN_DIR}/Plugin_OctreeSceneManager.dylib
|
||||
"${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_OctreeSceneManager.dylib" COPYONLY)
|
||||
|
||||
configure_file(${OGRE_PLUGIN_DIR}/Plugin_ParticleFX.dylib
|
||||
"${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_ParticleFX.dylib" COPYONLY)
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "Release" OR
|
||||
${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo")
|
||||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
|
||||
else()
|
||||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
||||
endif()
|
||||
|
||||
foreach(plugin ${USED_OGRE_PLUGINS})
|
||||
configure_file("${OGRE_PLUGIN_DIR}/${plugin}.dylib"
|
||||
"${APP_BUNDLE_DIR}/Contents/Plugins/${plugin}.dylib"
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
endif (APPLE)
|
||||
|
||||
|
||||
# Compiler settings
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
#add_definitions (-Wall -Werror)
|
||||
add_definitions (-Wall)
|
||||
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-unused-but-set-parameter -Wno-reorder)
|
||||
endif (CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
# Apple bundling
|
||||
# TODO REWRITE!
|
||||
if (APPLE)
|
||||
set(MISC_FILES
|
||||
${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg
|
||||
${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg)
|
||||
|
||||
set(OGRE_PLUGINS
|
||||
${APP_BUNDLE_DIR}/Contents/Plugins/*)
|
||||
|
||||
install(FILES ${MISC_FILES} DESTINATION ../MacOS)
|
||||
install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Plugins" DESTINATION ..)
|
||||
install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Resources/resources" DESTINATION ../Resources)
|
||||
set(CPACK_GENERATOR "Bundle")
|
||||
set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist")
|
||||
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns")
|
||||
set(CPACK_BUNDLE_NAME "OpenMW")
|
||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||
|
||||
include(CPack)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-arch i386")
|
||||
set(CMAKE_CXX_FLAGS "-arch i386")
|
||||
|
||||
endif (APPLE)
|
||||
|
||||
|
||||
if(DPKG_PROGRAM)
|
||||
SET(CMAKE_INSTALL_PREFIX "/usr")
|
||||
|
||||
|
@ -327,7 +314,7 @@ if(DPKG_PROGRAM)
|
|||
|
||||
SET(CPACK_GENERATOR "DEB")
|
||||
SET(CPACK_PACKAGE_NAME "openmw")
|
||||
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.com")
|
||||
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.org")
|
||||
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PACKAGE_MAINTAINER}")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A reimplementation of The Elder Scrolls III: Morrowind
|
||||
|
@ -352,6 +339,57 @@ if(DPKG_PROGRAM)
|
|||
include(CPack)
|
||||
endif(DPKG_PROGRAM)
|
||||
|
||||
if(WIN32)
|
||||
FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*")
|
||||
INSTALL(FILES ${files} DESTINATION ".")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||
|
||||
SET(CPACK_GENERATOR "NSIS")
|
||||
SET(CPACK_PACKAGE_NAME "OpenMW")
|
||||
SET(CPACK_PACKAGE_VENDOR "OpenMW.org")
|
||||
SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;esmtool;Esmtool;omwlauncher;OpenMW Launcher")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
|
||||
SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt")
|
||||
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW")
|
||||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
|
||||
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico")
|
||||
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico")
|
||||
# SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
||||
|
||||
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
||||
if(EXISTS ${VCREDIST32})
|
||||
INSTALL(FILES ${VCREDIST32} DESTINATION "redist")
|
||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q'" )
|
||||
endif(EXISTS ${VCREDIST32})
|
||||
|
||||
SET(VCREDIST64 "${OpenMW_BINARY_DIR}/vcredist_x64.exe")
|
||||
if(EXISTS ${VCREDIST64})
|
||||
INSTALL(FILES ${VCREDIST64} DESTINATION "redist")
|
||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q'" )
|
||||
endif(EXISTS ${VCREDIST64})
|
||||
|
||||
SET(OALREDIST "${OpenMW_BINARY_DIR}/oalinst.exe")
|
||||
if(EXISTS ${OALREDIST})
|
||||
INSTALL(FILES ${OALREDIST} DESTINATION "redist")
|
||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
|
||||
ExecWait '\\\"$INSTDIR\\\\redist\\\\oalinst.exe\\\" /s'" )
|
||||
endif(EXISTS ${OALREDIST})
|
||||
|
||||
if(CMAKE_CL_64)
|
||||
SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
endif(WIN32)
|
||||
|
||||
# Components
|
||||
add_subdirectory (components)
|
||||
|
||||
|
@ -384,6 +422,45 @@ if (WIN32)
|
|||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||
|
||||
# Play a bit with the warning levels
|
||||
|
||||
set(WARNINGS "/Wall") # Since windows can only disable specific warnings, not enable them
|
||||
|
||||
set(WARNINGS_DISABLE
|
||||
# Warnings that aren't enabled normally and don't need to be enabled
|
||||
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
||||
# Not going to bother commenting them as they tend to warn on every standard library files
|
||||
4061 4263 4264 4266 4350 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
|
||||
|
||||
# Warnings that are thrown on standard libraries and not OpenMW
|
||||
4347 # Non-template function with same name and parameter count as template function
|
||||
4365 # Variable signed/unsigned mismatch
|
||||
4510 4512 # Unable to generate copy constructor/assignment operator as it's not public in the base
|
||||
4706 # Assignment in conditional expression
|
||||
4738 # Storing 32-bit float result in memory, possible loss of performance
|
||||
4986 # Undocumented warning that occurs in the crtdbg.h file
|
||||
4996 # Function was declared deprecated
|
||||
|
||||
# OpenMW specific warnings
|
||||
4099 # Type mismatch, declared class or struct is defined with other type
|
||||
4100 # Unreferenced formal parameter (-Wunused-parameter)
|
||||
4127 # Conditional expression is constant
|
||||
4242 # Storing value in a variable of a smaller type, possible loss of data
|
||||
4244 # Storing value of one type in variable of another (size_t in int, for example)
|
||||
4305 # Truncating value (double to float, for example)
|
||||
4309 # Variable overflow, trying to store 128 in a signed char for example
|
||||
4355 # Using 'this' in member initialization list
|
||||
4701 # Potentially uninitialized local variable used
|
||||
)
|
||||
|
||||
foreach(d ${WARNINGS_DISABLE})
|
||||
set(WARNINGS "${WARNINGS} /wd${d}")
|
||||
endforeach(d)
|
||||
|
||||
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
|
||||
endif(MSVC)
|
||||
|
||||
# Same for MinGW
|
||||
|
@ -406,3 +483,82 @@ if (WIN32)
|
|||
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||
endif()
|
||||
|
||||
# Apple bundling
|
||||
if (APPLE)
|
||||
set(INSTALL_SUBDIR OpenMW)
|
||||
|
||||
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
|
||||
install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
||||
set(PLUGINS "")
|
||||
|
||||
# Scan Plugins dir for *.dylibs
|
||||
set(PLUGIN_SEARCH_ROOT "${APP_BUNDLE_DIR}/Contents/Plugins")
|
||||
file(GLOB_RECURSE ALL_PLUGINS "${PLUGIN_SEARCH_ROOT}/*.dylib")
|
||||
|
||||
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins")
|
||||
foreach(PLUGIN ${ALL_PLUGINS})
|
||||
string(REPLACE "${PLUGIN_SEARCH_ROOT}/" "" PLUGIN_RELATIVE "${PLUGIN}")
|
||||
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
|
||||
endforeach()
|
||||
|
||||
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
|
||||
set(DIRS "")
|
||||
|
||||
# Overriding item resolving during installation, it needed if
|
||||
# some library already has be "fixed up", i.e. its id name contains @executable_path,
|
||||
# but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK.
|
||||
# Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case.
|
||||
#
|
||||
# Current limitations:
|
||||
# 1. Handles only frameworks, not simple libs
|
||||
INSTALL(CODE "
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
|
||||
|
||||
set(OPENMW_RESOLVED_ITEMS \"\")
|
||||
|
||||
function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var)
|
||||
if(item MATCHES \"@executable_path\" AND NOT \${\${resolved_var}})
|
||||
if (item MATCHES \"Frameworks\") # if it is a framework
|
||||
# get last segment of path
|
||||
get_filename_component(fname \"\${item}\" NAME_WE)
|
||||
find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /Library/Frameworks)
|
||||
if (ri)
|
||||
message(STATUS \"found \${ri} for \${item}\")
|
||||
string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item})
|
||||
set(ri \"\${ri}\${item_part}\")
|
||||
set(\${resolved_item_var} \${ri} PARENT_SCOPE)
|
||||
set(\${resolved_var} 1 PARENT_SCOPE)
|
||||
set(OPENMW_RESOLVED_ITEMS \${_OPENMW_RESOLVED_ITEMS} \${ri})
|
||||
endif()
|
||||
else()
|
||||
# code path for standard (non-framework) libs (ogre & qt pugins)
|
||||
endif()
|
||||
endif()
|
||||
endfunction(gp_resolve_item_override)
|
||||
|
||||
cmake_policy(SET CMP0009 OLD)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${APPS}\" \"${PLUGINS}\" \"${DIRS}\")
|
||||
" COMPONENT Runtime)
|
||||
|
||||
include(CPack)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-arch i386")
|
||||
set(CMAKE_CXX_FLAGS "-arch i386")
|
||||
|
||||
endif (APPLE)
|
||||
|
|
142
README_Mac.md
142
README_Mac.md
|
@ -1,80 +1,79 @@
|
|||
NOTE: This README is for ardekantur's Mac branch of OpenMW. A README
|
||||
for the main branch has yet to be written. If you want to submit one,
|
||||
please send me a message!
|
||||
#Getting OpenMW Working on OS X
|
||||
|
||||
OpenMW
|
||||
======
|
||||
## Initial setup
|
||||
First of all, clone OpenMW repo.
|
||||
|
||||
From the [official website][]:
|
||||
$ git clone github.com/zinnschlag/openmw
|
||||
|
||||
> OpenMW is an attempt to reimplement the popular role playing game
|
||||
Morrowind. It aims to be a fully playable, open source
|
||||
implementation of the game. You must own Morrowind to use OpenMW.
|
||||
Or use your github url if you forked.
|
||||
|
||||
About dependencies: I prefer not to install them globally (i. e. in /usr/local/), so I'm installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs.
|
||||
|
||||
About This Project
|
||||
------------------
|
||||
It's useful to create env var for lib install prefix:
|
||||
|
||||
$ export OMW_LIB_PREFIX=$HOME/path/libs/root`
|
||||
|
||||
This specific repository is a branch of OpenMW intended to keep pace
|
||||
with development of the project in order to provide a Mac build for
|
||||
interested parties to contribute. This is not an official, sanctioned
|
||||
branch of the OpenMW project. I will only be able to answer specific
|
||||
questions about getting this project running on Mac OS X, **no other
|
||||
platform**. I will not even be able to guarantee my changes maintain
|
||||
backwards compatibility against builds in other operating systems. You
|
||||
have been warned.
|
||||
Most of libs can be installed from [Homebrew][homebrew]. Only mpg123 needs to be installed from source (due to lack of universal compilation support). I think that some of libs can be installed from MacPorts or Fink too.
|
||||
|
||||
As OpenMW currently only supports i386 architecture on OS X, denendencies also should support it. Set some env vars in current terminal:
|
||||
|
||||
Getting OpenMW Working
|
||||
----------------------
|
||||
|
||||
1. Clone this repository.
|
||||
2. Note about libs: I prefer not to install them globally (i. e. in /usr/local/), so I installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs.
|
||||
It's useful to create env var for lib install prefix:
|
||||
$ export OMW_LIB_PREFIX=$HOME/path/libs/root
|
||||
|
||||
3. First of all, set for current terminal some env vars:
|
||||
$ export CFLAGS="-arch i386"
|
||||
$ export CXXFLAGS="-arch i386"
|
||||
$ export LDFLAGS="-arch i386"
|
||||
All libs will build with correct architecture.
|
||||
If you close your terminal, you should set env vars again before pcoceeding to next steps!
|
||||
|
||||
4. Download [boost][] (tested with 1.45) and install it with the following command:
|
||||
If you close your terminal, you should set env vars again before pcoceeding to next steps!
|
||||
|
||||
## Boost
|
||||
Download [boost][boost] and install it with the following command:
|
||||
|
||||
$ cd /path/to/boost/source
|
||||
$ ./bootstrap.sh --prefix=$OMW_LIB_PREFIX
|
||||
$ ./bjam --build-dir=build --layout=versioned \
|
||||
--toolset=darwin architecture=x86 address-model=32 \
|
||||
--link-shared,static --prefix=$OMW_LIB_PREFIX install
|
||||
|
||||
|
||||
Alternatively you can install boost with homebrew:
|
||||
|
||||
$ brew install boost --universal
|
||||
|
||||
5. Download [Ogre][] SDK (tested with 1.7.2), unpack it and move
|
||||
`lib/Release/Ogre.framework` into `Library/Frameworks`.
|
||||
I think MacPorts also should support universal build for boost.
|
||||
|
||||
6. Download [OIS][] and use the XCode project provided in
|
||||
`ois/Mac/XCode-2.2`. Be sure to set your build architecture to
|
||||
`i386` and your SDK platform to either 10.5 or 10.6. Once it
|
||||
builds, move `ois/Mac/XCode-2.2/build/Debug/OIS.framework` to
|
||||
`/Library/Frameworks`.
|
||||
## Ogre
|
||||
Download [Ogre][] SDK (tested with 1.7.3), unpack it somewhere and move
|
||||
`lib/Release/Ogre.framework` into `/Library/Frameworks`.
|
||||
|
||||
## OIS
|
||||
Download patched [OIS][] and use the XCode project provided. Be sure to set your build architecture to
|
||||
`i386`. Once it built, locate built OIS.framework with Xcode and move it to `/Library/Frameworks`.
|
||||
|
||||
## mpg123
|
||||
Download [MPG 123][mpg123] and build it:
|
||||
|
||||
7. Download [mpg123][] and build it:
|
||||
$ cd /path/to/mpg123/source
|
||||
$ ./configure --prefix=$OMW_LIB_PREFIX --disable-debug \
|
||||
--disable-dependency-tracking \
|
||||
--with-optimization=4 \
|
||||
--with-audio=coreaudio \
|
||||
--with-default-audio=coreaudio \
|
||||
--with-audio=dummy \
|
||||
--with-default-audio=dummy \
|
||||
--with-cpu=sse_alone \
|
||||
$ make install
|
||||
|
||||
8. Download [libsndfile][] and build it:
|
||||
## libsndfile
|
||||
Download [libsndfile][] and build it:
|
||||
|
||||
$ cd /path/to/libsndfile/source
|
||||
$ ./configure --prefix=$OMW_LIB_PREFIX \
|
||||
--disable-dependency-tracking
|
||||
$ make install
|
||||
|
||||
9. Download [Bullet][] and build it:
|
||||
or install with homebrew:
|
||||
|
||||
$ brew install libsndfile --universal
|
||||
|
||||
## Bullet
|
||||
Download [Bullet][] and build it:
|
||||
|
||||
$ cd /path/to/bullet/source
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
|
@ -87,12 +86,25 @@ Getting OpenMW Working
|
|||
-G"Unix Makefiles" ../
|
||||
$ make install
|
||||
|
||||
10. Generate the Makefile for OpenMW as follows and build OpenMW:
|
||||
or install with homebrew:
|
||||
|
||||
$ brew install bullet --HEAD --universal
|
||||
|
||||
I prefer head because 2.79 has some issue which causes OpenMW to lag. Also you can edit formula and install 2.77, which is stable and haven't mentioned issue.
|
||||
|
||||
## Qt
|
||||
Install [Qt][qt]. Qt SDK distributed by Nokia is not an option because it's 64 bit only, and OpenMW currently doesn't build for 64 bit on OS X. I'm installing it from Homebrew:
|
||||
|
||||
$ brew install qt --universal
|
||||
|
||||
## Run CMake
|
||||
Generate the Makefile for OpenMW as follows and build OpenMW:
|
||||
|
||||
$ mkdir /path/to/openmw/build/dir
|
||||
$ cd /path/to/open/build/dir
|
||||
$ cmake \
|
||||
-D CMAKE_OSX_ARCHITECTURES=i386 \
|
||||
-D OGRESDK=/path/to/ogre/sdk \
|
||||
-D OGRE_SDK=/path/to/ogre/sdk \
|
||||
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
|
||||
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
|
||||
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||
|
@ -106,27 +118,43 @@ Getting OpenMW Working
|
|||
-D BULLET_INCLUDE_DIR=$OMW_LIB_PREFIX/include/bullet/ \
|
||||
-G "Unix Makefiles" /path/to/openmw/source/dir
|
||||
$ make
|
||||
You can use -G"Xcode" if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
|
||||
if you prefer Eclipse. You also can specify -D CMAKE_BUILD_TYPE=Debug for debug
|
||||
build.
|
||||
|
||||
You can use `-G"Xcode"` if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
|
||||
if you prefer Eclipse. You also can specify `-D CMAKE_BUILD_TYPE=Debug` for debug
|
||||
build. As for CMake 2.8.7 and Xcode 4.3, Xcode generator is broken. Sadly Eclipse CDT also cannot import generated project at least on my machine.
|
||||
|
||||
11. Copy your Morrowind `Data Files` directory into the OpenMW build dir
|
||||
with the name `data` or create symlink:
|
||||
$ ln -s /path/to/morrowind/data/files /path/to/openmw/build/dir/data
|
||||
If all libs installed via homebrew (excluding mpg123), then command would be even simplier:
|
||||
|
||||
$ cmake \
|
||||
-D CMAKE_OSX_ARCHITECTURES="i386" \
|
||||
-D OGRE_SDK=/path/to/ogre/sdk \
|
||||
-D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \
|
||||
-D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||
-G "Unix Makefiles" /path/to/openmw/source/dir
|
||||
$ make
|
||||
|
||||
Note for users with recent Xcode versions: you must explicitly specify what set of compilers do you use! If not, gcc will be used for C and Clang for C++. Just add this two -D's to command: `-D CMAKE_C_COMPILER=/usr/bin/clang` and `-D CMAKE_CXX_COMPILER=/usr/bin/clang`
|
||||
|
||||
Note for Xcode 4.3 users: you should specify full path to used SDK, because current CMake (2.8.7) couldn't find SDKs inside Xcode app bundle:
|
||||
|
||||
-D CMAKE_OSX_SYSROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk"
|
||||
|
||||
# Run
|
||||
From your build directory run:
|
||||
|
||||
12. From your build directory run:
|
||||
$ OpenMW.app/Contents/MacOS/openmw
|
||||
or:
|
||||
or:
|
||||
|
||||
$ open OpenMW.app
|
||||
Enjoy!
|
||||
|
||||
|
||||
Enjoy!
|
||||
|
||||
[homebrew]: https://github.com/mxcl/homebrew
|
||||
[boost]: http://www.boost.org
|
||||
[Ogre]: http://www.ogre3d.org
|
||||
[Bullet]: http://bulletphysics.org
|
||||
[OIS]: http://wgois.sf.net
|
||||
[OIS]: https://github.com/corristo/ois-fork
|
||||
[mpg123]: http://www.mpg123.de
|
||||
[libsndfile]: http://www.mega-nerd.com/libsndfile
|
||||
[official website]: http://openmw.com
|
||||
[Will Thimbleby's Ogre Framework]: http://www.thimbleby.net/ogre/
|
||||
[qt]: http://qt.nokia.com/
|
|
@ -1,6 +1,4 @@
|
|||
set(ESMTOOL
|
||||
esmtool_cmd.c
|
||||
esmtool_cmd.h
|
||||
esmtool.cpp
|
||||
)
|
||||
source_group(apps\\esmtool FILES ${ESMTOOL})
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
esmtool_cmd.c: esmtool.ggo
|
||||
gengetopt < esmtool.ggo
|
||||
|
||||
clean:
|
||||
rm esmtool_cmd.c esmtool_cmd.h
|
|
@ -1,35 +1,138 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <components/esm/esm_reader.hpp>
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "esmtool_cmd.h"
|
||||
|
||||
#include <iostream>
|
||||
#define ESMTOOL_VERSION 1.1
|
||||
|
||||
using namespace std;
|
||||
using namespace ESM;
|
||||
|
||||
// Create a local alias for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void printRaw(ESMReader &esm);
|
||||
void loadCell(Cell &cell, ESMReader &esm, bool quiet);
|
||||
|
||||
int main(int argc, char**argv)
|
||||
// Based on the legacy struct
|
||||
struct Arguments
|
||||
{
|
||||
gengetopt_args_info info;
|
||||
unsigned int raw_given;
|
||||
unsigned int quiet_given;
|
||||
unsigned int loadcells_given;
|
||||
std::string encoding;
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
if(cmdline_parser(argc, argv, &info) != 0)
|
||||
return 1;
|
||||
bool parseOptions (int argc, char** argv, Arguments &info)
|
||||
{
|
||||
bpo::options_description desc("Inspect and extract from Morrowind ES files (ESM, ESP, ESS)\nSyntax: esmtool [options] file \nAllowed options");
|
||||
|
||||
if(info.inputs_num != 1)
|
||||
desc.add_options()
|
||||
("help,h", "print help message.")
|
||||
("version,v", "print version information and quit.")
|
||||
("raw,r", "Show an unformattet list of all records and subrecords.")
|
||||
("quiet,q", "Supress all record information. Useful for speed tests.")
|
||||
("loadcells,C", "Browse through contents of all cells.")
|
||||
|
||||
( "encoding,e", bpo::value<std::string>(&(info.encoding))->
|
||||
default_value("win1252"),
|
||||
"Character encoding used in ESMTool:\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")
|
||||
;
|
||||
|
||||
std::string finalText = "\nIf no option is given, the default action is to parse all records in the archive\nand display diagnostic information.";
|
||||
|
||||
// input-file is hidden and used as a positional argument
|
||||
bpo::options_description hidden("Hidden Options");
|
||||
|
||||
hidden.add_options()
|
||||
( "input-file,i", bpo::value< vector<std::string> >(), "input file")
|
||||
;
|
||||
|
||||
bpo::positional_options_description p;
|
||||
p.add("input-file", -1);
|
||||
|
||||
// there might be a better way to do this
|
||||
bpo::options_description all;
|
||||
all.add(desc).add(hidden);
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
|
||||
.options(all).positional(p).run();
|
||||
|
||||
bpo::variables_map variables;
|
||||
bpo::store(valid_opts, variables);
|
||||
bpo::notify(variables);
|
||||
|
||||
if (variables.count ("help"))
|
||||
{
|
||||
if(info.inputs_num == 0)
|
||||
cout << "ERROR: missing ES file\n\n";
|
||||
else
|
||||
cout << "ERROR: more than one ES file specified\n\n";
|
||||
cmdline_parser_print_help();
|
||||
return 1;
|
||||
std::cout << desc << finalText << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (variables.count ("version"))
|
||||
{
|
||||
std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !variables.count("input-file") )
|
||||
{
|
||||
std::cout << "\nERROR: missing ES file\n\n";
|
||||
std::cout << desc << finalText << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// handling gracefully the user adding multiple files
|
||||
if (variables["input-file"].as< vector<std::string> >().size() > 1)
|
||||
{
|
||||
std::cout << "\nERROR: more than one ES file specified\n\n";
|
||||
std::cout << desc << finalText << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
info.filename = variables["input-file"].as< vector<std::string> >()[0];
|
||||
|
||||
info.raw_given = variables.count ("raw");
|
||||
info.quiet_given = variables.count ("quiet");
|
||||
info.loadcells_given = variables.count ("loadcells");
|
||||
|
||||
// Font encoding settings
|
||||
info.encoding = variables["encoding"].as<std::string>();
|
||||
if (info.encoding == "win1250")
|
||||
{
|
||||
std::cout << "Using Central and Eastern European font encoding." << std::endl;
|
||||
}
|
||||
else if (info.encoding == "win1251")
|
||||
{
|
||||
std::cout << "Using Cyrillic font encoding." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(info.encoding != "win1252")
|
||||
{
|
||||
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
|
||||
info.encoding = "win1252";
|
||||
}
|
||||
std::cout << "Using default (English) font encoding." << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
Arguments info;
|
||||
if(!parseOptions (argc, argv, info))
|
||||
return 1;
|
||||
|
||||
ESMReader esm;
|
||||
const char* filename = info.inputs[0];
|
||||
esm.setEncoding(info.encoding);
|
||||
|
||||
string filename = info.filename;
|
||||
cout << "\nFile: " << filename << endl;
|
||||
|
||||
try {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package "esmtool"
|
||||
version "1.0"
|
||||
purpose "Inspect and extract from Morrowind ES files (ESM, ESP, ESS)"
|
||||
args "--unamed-opts=ES-FILE -F esmtool_cmd -G"
|
||||
|
||||
option "raw" r "Show an unformattet list of all records and subrecords" optional
|
||||
option "quiet" q "Supress all record information. Useful for speed tests." optional
|
||||
option "loadcells" C "Browse through contents of all cells." optional
|
||||
|
||||
text "\nIf no option is given, the default action is to parse all records in the archive and display diagnostic information."
|
File diff suppressed because it is too large
Load diff
|
@ -1,179 +0,0 @@
|
|||
/** @file esmtool_cmd.h
|
||||
* @brief The header file for the command line option parser
|
||||
* generated by GNU Gengetopt version 2.22.2
|
||||
* http://www.gnu.org/software/gengetopt.
|
||||
* DO NOT modify this file, since it can be overwritten
|
||||
* @author GNU Gengetopt by Lorenzo Bettini */
|
||||
|
||||
#ifndef ESMTOOL_CMD_H
|
||||
#define ESMTOOL_CMD_H
|
||||
|
||||
/* If we use autoconf. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* for FILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifndef CMDLINE_PARSER_PACKAGE
|
||||
/** @brief the program name (used for printing errors) */
|
||||
#define CMDLINE_PARSER_PACKAGE "esmtool"
|
||||
#endif
|
||||
|
||||
#ifndef CMDLINE_PARSER_PACKAGE_NAME
|
||||
/** @brief the complete program name (used for help and version) */
|
||||
#define CMDLINE_PARSER_PACKAGE_NAME "esmtool"
|
||||
#endif
|
||||
|
||||
#ifndef CMDLINE_PARSER_VERSION
|
||||
/** @brief the program version */
|
||||
#define CMDLINE_PARSER_VERSION "1.0"
|
||||
#endif
|
||||
|
||||
/** @brief Where the command line options are stored */
|
||||
struct gengetopt_args_info
|
||||
{
|
||||
const char *help_help; /**< @brief Print help and exit help description. */
|
||||
const char *version_help; /**< @brief Print version and exit help description. */
|
||||
const char *raw_help; /**< @brief Show an unformattet list of all records and subrecords help description. */
|
||||
const char *quiet_help; /**< @brief Supress all record information. Useful for speed tests. help description. */
|
||||
const char *loadcells_help; /**< @brief Browse through contents of all cells. help description. */
|
||||
|
||||
unsigned int help_given ; /**< @brief Whether help was given. */
|
||||
unsigned int version_given ; /**< @brief Whether version was given. */
|
||||
unsigned int raw_given ; /**< @brief Whether raw was given. */
|
||||
unsigned int quiet_given ; /**< @brief Whether quiet was given. */
|
||||
unsigned int loadcells_given ; /**< @brief Whether loadcells was given. */
|
||||
|
||||
char **inputs ; /**< @brief unamed options (options without names) */
|
||||
unsigned inputs_num ; /**< @brief unamed options number */
|
||||
} ;
|
||||
|
||||
/** @brief The additional parameters to pass to parser functions */
|
||||
struct cmdline_parser_params
|
||||
{
|
||||
int override; /**< @brief whether to override possibly already present options (default 0) */
|
||||
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
|
||||
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
|
||||
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
|
||||
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
|
||||
} ;
|
||||
|
||||
/** @brief the purpose string of the program */
|
||||
extern const char *gengetopt_args_info_purpose;
|
||||
/** @brief the usage string of the program */
|
||||
extern const char *gengetopt_args_info_usage;
|
||||
/** @brief all the lines making the help output */
|
||||
extern const char *gengetopt_args_info_help[];
|
||||
|
||||
/**
|
||||
* The command line parser
|
||||
* @param argc the number of command line options
|
||||
* @param argv the command line options
|
||||
* @param args_info the structure where option information will be stored
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser (int argc, char * const *argv,
|
||||
struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* The command line parser (version with additional parameters - deprecated)
|
||||
* @param argc the number of command line options
|
||||
* @param argv the command line options
|
||||
* @param args_info the structure where option information will be stored
|
||||
* @param override whether to override possibly already present options
|
||||
* @param initialize whether to initialize the option structure my_args_info
|
||||
* @param check_required whether to check that all required options were provided
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
* @deprecated use cmdline_parser_ext() instead
|
||||
*/
|
||||
int cmdline_parser2 (int argc, char * const *argv,
|
||||
struct gengetopt_args_info *args_info,
|
||||
int override, int initialize, int check_required);
|
||||
|
||||
/**
|
||||
* The command line parser (version with additional parameters)
|
||||
* @param argc the number of command line options
|
||||
* @param argv the command line options
|
||||
* @param args_info the structure where option information will be stored
|
||||
* @param params additional parameters for the parser
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser_ext (int argc, char * const *argv,
|
||||
struct gengetopt_args_info *args_info,
|
||||
struct cmdline_parser_params *params);
|
||||
|
||||
/**
|
||||
* Save the contents of the option struct into an already open FILE stream.
|
||||
* @param outfile the stream where to dump options
|
||||
* @param args_info the option struct to dump
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser_dump(FILE *outfile,
|
||||
struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* Save the contents of the option struct into a (text) file.
|
||||
* This file can be read by the config file parser (if generated by gengetopt)
|
||||
* @param filename the file where to save
|
||||
* @param args_info the option struct to save
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser_file_save(const char *filename,
|
||||
struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* Print the help
|
||||
*/
|
||||
void cmdline_parser_print_help(void);
|
||||
/**
|
||||
* Print the version
|
||||
*/
|
||||
void cmdline_parser_print_version(void);
|
||||
|
||||
/**
|
||||
* Initializes all the fields a cmdline_parser_params structure
|
||||
* to their default values
|
||||
* @param params the structure to initialize
|
||||
*/
|
||||
void cmdline_parser_params_init(struct cmdline_parser_params *params);
|
||||
|
||||
/**
|
||||
* Allocates dynamically a cmdline_parser_params structure and initializes
|
||||
* all its fields to their default values
|
||||
* @return the created and initialized cmdline_parser_params structure
|
||||
*/
|
||||
struct cmdline_parser_params *cmdline_parser_params_create(void);
|
||||
|
||||
/**
|
||||
* Initializes the passed gengetopt_args_info structure's fields
|
||||
* (also set default values for options that have a default)
|
||||
* @param args_info the structure to initialize
|
||||
*/
|
||||
void cmdline_parser_init (struct gengetopt_args_info *args_info);
|
||||
/**
|
||||
* Deallocates the string fields of the gengetopt_args_info structure
|
||||
* (but does not deallocate the structure itself)
|
||||
* @param args_info the structure to deallocate
|
||||
*/
|
||||
void cmdline_parser_free (struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* Checks that all the required options were specified
|
||||
* @param args_info the structure to check
|
||||
* @param prog_name the name of the program that will be used to print
|
||||
* possible errors
|
||||
* @return
|
||||
*/
|
||||
int cmdline_parser_required (struct gengetopt_args_info *args_info,
|
||||
const char *prog_name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* ESMTOOL_CMD_H */
|
|
@ -41,8 +41,11 @@ source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC
|
|||
find_package(Qt4 REQUIRED)
|
||||
set(QT_USE_QTGUI 1)
|
||||
|
||||
find_package(PNG REQUIRED)
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
# Set some platform specific settings
|
||||
if(WIN32)
|
||||
set(GUI_TYPE WIN32)
|
||||
set(QT_USE_QTMAIN TRUE)
|
||||
endif(WIN32)
|
||||
|
||||
QT4_ADD_RESOURCES(RCC_SRCS resources.qrc)
|
||||
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
|
||||
|
@ -50,7 +53,17 @@ QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
|
|||
include(${QT_USE_FILE})
|
||||
|
||||
# Main executable
|
||||
IF(OGRE_STATIC)
|
||||
IF(WIN32)
|
||||
ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL)
|
||||
set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES})
|
||||
ELSE(WIN32)
|
||||
ADD_DEFINITIONS(-DENABLE_PLUGIN_GL)
|
||||
set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_GL_LIBRARIES})
|
||||
ENDIF(WIN32)
|
||||
ENDIF(OGRE_STATIC)
|
||||
add_executable(omwlauncher
|
||||
${GUI_TYPE}
|
||||
${LAUNCHER}
|
||||
${RCC_SRCS}
|
||||
${MOC_SRCS}
|
||||
|
@ -59,8 +72,8 @@ add_executable(omwlauncher
|
|||
target_link_libraries(omwlauncher
|
||||
${Boost_LIBRARIES}
|
||||
${OGRE_LIBRARIES}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${QT_LIBRARIES}
|
||||
${PNG_LIBRARY}
|
||||
components
|
||||
)
|
||||
|
||||
|
@ -71,12 +84,16 @@ endif()
|
|||
if (APPLE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${APP_BUNDLE_DIR}/../launcher.qss")
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||
"${APP_BUNDLE_DIR}/../launcher.cfg")
|
||||
else()
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss")
|
||||
|
||||
# Fallback in case getGlobalDataPath does not point to resources
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg")
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}launcher.cfg")
|
||||
endif()
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#include <QtGui>
|
||||
|
||||
#include <components/esm/esm_reader.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include "datafilespage.hpp"
|
||||
#include "lineedit.hpp"
|
||||
|
@ -11,6 +9,23 @@
|
|||
#include "pluginsmodel.hpp"
|
||||
#include "pluginsview.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* Workaround for problems with whitespaces in paths in older versions of Boost library
|
||||
*/
|
||||
#if (BOOST_VERSION <= 104600)
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<>
|
||||
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
|
||||
{
|
||||
return boost::filesystem::path(arg);
|
||||
}
|
||||
|
||||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
using namespace ESM;
|
||||
using namespace std;
|
||||
|
||||
|
@ -26,7 +41,9 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2)
|
|||
return index1.row() <= index2.row();
|
||||
}
|
||||
|
||||
DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
||||
DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mCfgMgr(cfg)
|
||||
{
|
||||
mDataFilesModel = new QStandardItemModel(); // Contains all plugins with masters
|
||||
mPluginsModel = new PluginsModel(); // Contains selectable plugins
|
||||
|
@ -118,37 +135,139 @@ DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
|||
connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
|
||||
connect(mPluginsTable, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
|
||||
|
||||
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
|
||||
|
||||
|
||||
setupConfig();
|
||||
createActions();
|
||||
setupConfig();
|
||||
setupDataFiles();
|
||||
|
||||
}
|
||||
|
||||
void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
||||
void DataFilesPage::setupConfig()
|
||||
{
|
||||
// Put the paths in a boost::filesystem vector to use with Files::Collections
|
||||
Files::PathContainer dataDirs;
|
||||
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.cfg").string());
|
||||
QFile file(config);
|
||||
|
||||
foreach (const QString ¤tPath, paths) {
|
||||
dataDirs.push_back(boost::filesystem::path(currentPath.toStdString()));
|
||||
if (!file.exists()) {
|
||||
config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string());
|
||||
}
|
||||
|
||||
// Open our config file
|
||||
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
|
||||
file.close();
|
||||
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
}
|
||||
|
||||
mLauncherConfig->beginGroup("Profiles");
|
||||
QStringList profiles = mLauncherConfig->childGroups();
|
||||
|
||||
if (profiles.isEmpty()) {
|
||||
// Add a default profile
|
||||
profiles.append("Default");
|
||||
}
|
||||
|
||||
mProfilesComboBox->addItems(profiles);
|
||||
|
||||
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
|
||||
|
||||
if (currentProfile.isEmpty()) {
|
||||
// No current profile selected
|
||||
currentProfile = "Default";
|
||||
}
|
||||
|
||||
const int currentIndex = mProfilesComboBox->findText(currentProfile);
|
||||
if (currentIndex != -1) {
|
||||
// Profile is found
|
||||
mProfilesComboBox->setCurrentIndex(currentIndex);
|
||||
}
|
||||
|
||||
mLauncherConfig->endGroup();
|
||||
}
|
||||
|
||||
|
||||
void DataFilesPage::setupDataFiles()
|
||||
{
|
||||
// We use the Configuration Manager to retrieve the configuration values
|
||||
boost::program_options::variables_map variables;
|
||||
boost::program_options::options_description desc;
|
||||
|
||||
desc.add_options()
|
||||
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
|
||||
// ("data-local", boost::program_options::value<std::string>()->default_value(""))
|
||||
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
||||
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
|
||||
|
||||
mCfgMgr.readConfiguration(variables, desc);
|
||||
|
||||
// Put the paths in a boost::filesystem vector to use with Files::Collections
|
||||
Files::PathContainer dataDirs(variables["data"].as<Files::PathContainer>());
|
||||
mDataDirs = dataDirs;
|
||||
|
||||
// std::string local = variables["data-local"].as<std::string>();
|
||||
// if (!local.empty()) {
|
||||
// mDataLocal.push_back(Files::PathContainer::value_type(local));
|
||||
// dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||
// }
|
||||
|
||||
if (dataDirs.size()>1)
|
||||
dataDirs.resize (1);
|
||||
|
||||
mCfgMgr.processPaths(dataDirs);
|
||||
|
||||
while (dataDirs.empty()) {
|
||||
// No valid data files directory found
|
||||
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error detecting Morrowind installation");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
|
||||
The directory containing the Data Files was not found.<br><br> \
|
||||
Press \"Browse...\" to specify the location manually.<br>"));
|
||||
|
||||
QAbstractButton *dirSelectButton =
|
||||
msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == dirSelectButton) {
|
||||
|
||||
QString dataDir = QFileDialog::getExistingDirectory(
|
||||
this, tr("Select Data Files Directory"),
|
||||
"/home",
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
|
||||
dataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString()));
|
||||
mDataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString()));
|
||||
} else {
|
||||
// Cancel
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if cancel was clicked because we can't exit from while loop
|
||||
if (dataDirs.empty()) {
|
||||
QApplication::exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a file collection for the dataDirs
|
||||
Files::Collections mFileCollections(dataDirs, strict);
|
||||
Files::Collections fileCollections(dataDirs, !variables["fs-strict"].as<bool>());
|
||||
|
||||
// First we add all the master files
|
||||
const Files::MultiDirCollection &esm = mFileCollections.getCollection(".esm");
|
||||
const Files::MultiDirCollection &esm = fileCollections.getCollection(".esm");
|
||||
unsigned int i = 0; // Row number
|
||||
|
||||
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter)
|
||||
{
|
||||
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter) {
|
||||
QString currentMaster = QString::fromStdString(
|
||||
boost::filesystem::path (iter->second.filename()).string());
|
||||
|
||||
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
|
||||
|
||||
if (itemList.isEmpty()) // Master is not yet in the widget
|
||||
{
|
||||
if (itemList.isEmpty()) { // Master is not yet in the widget
|
||||
mMastersWidget->insertRow(i);
|
||||
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
|
||||
mMastersWidget->setItem(i, 0, item);
|
||||
|
@ -157,14 +276,13 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
|||
}
|
||||
|
||||
// Now on to the plugins
|
||||
const Files::MultiDirCollection &esp = mFileCollections.getCollection(".esp");
|
||||
const Files::MultiDirCollection &esp = fileCollections.getCollection(".esp");
|
||||
|
||||
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter)
|
||||
{
|
||||
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter) {
|
||||
ESMReader fileReader;
|
||||
QStringList availableMasters; // Will contain all found masters
|
||||
|
||||
fileReader.setEncoding("win1252"); // FIXME: This should be configurable!
|
||||
fileReader.setEncoding(variables["encoding"].as<std::string>());
|
||||
fileReader.open(iter->second.string());
|
||||
|
||||
// First we fill the availableMasters and the mMastersWidget
|
||||
|
@ -176,8 +294,7 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
|||
|
||||
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
|
||||
|
||||
if (itemList.isEmpty()) // Master is not yet in the widget
|
||||
{
|
||||
if (itemList.isEmpty()) { // Master is not yet in the widget
|
||||
mMastersWidget->insertRow(i);
|
||||
|
||||
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
|
||||
|
@ -234,54 +351,6 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
|||
readConfig();
|
||||
}
|
||||
|
||||
void DataFilesPage::setupConfig()
|
||||
{
|
||||
Cfg::ConfigurationManager cfg;
|
||||
|
||||
QString config = (cfg.getRuntimeConfigPath() / "launcher.cfg").string().c_str();
|
||||
QFile file(config);
|
||||
|
||||
if (!file.exists()) {
|
||||
config = QString::fromStdString((cfg.getLocalConfigPath() / "launcher.cfg").string());
|
||||
}
|
||||
|
||||
file.setFileName(config); // Just for displaying information
|
||||
|
||||
// Open our config file
|
||||
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
|
||||
mLauncherConfig->sync();
|
||||
|
||||
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
}
|
||||
|
||||
mLauncherConfig->beginGroup("Profiles");
|
||||
QStringList profiles = mLauncherConfig->childGroups();
|
||||
|
||||
if (profiles.isEmpty()) {
|
||||
// Add a default profile
|
||||
profiles.append("Default");
|
||||
}
|
||||
|
||||
mProfilesComboBox->addItems(profiles);
|
||||
|
||||
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
|
||||
|
||||
if (currentProfile.isEmpty()) {
|
||||
// No current profile selected
|
||||
currentProfile = "Default";
|
||||
}
|
||||
mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(currentProfile));
|
||||
|
||||
mLauncherConfig->endGroup();
|
||||
|
||||
// Now we connect the combobox to do something if the profile changes
|
||||
// This prevents strange behaviour while reading and appending the profiles
|
||||
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
|
||||
}
|
||||
|
||||
void DataFilesPage::createActions()
|
||||
{
|
||||
// Refresh the plugins
|
||||
|
@ -414,18 +483,18 @@ void DataFilesPage::deleteProfile()
|
|||
return;
|
||||
}
|
||||
|
||||
QMessageBox deleteMessageBox(this);
|
||||
deleteMessageBox.setWindowTitle(tr("Delete Profile"));
|
||||
deleteMessageBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
|
||||
deleteMessageBox.setIcon(QMessageBox::Warning);
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Profile"));
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||
msgBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
|
||||
|
||||
QAbstractButton *deleteButton =
|
||||
deleteMessageBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||
msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||
|
||||
deleteMessageBox.addButton(QMessageBox::Cancel);
|
||||
msgBox.exec();
|
||||
|
||||
deleteMessageBox.exec();
|
||||
|
||||
if (deleteMessageBox.clickedButton() == deleteButton) {
|
||||
if (msgBox.clickedButton() == deleteButton) {
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
|
@ -482,7 +551,6 @@ void DataFilesPage::moveUp()
|
|||
void DataFilesPage::moveDown()
|
||||
{
|
||||
// Shift the selected plugins down one row
|
||||
|
||||
if (!mPluginsTable->selectionModel()->hasSelection()) {
|
||||
return;
|
||||
}
|
||||
|
@ -898,9 +966,18 @@ void DataFilesPage::filterChanged(const QString filter)
|
|||
|
||||
void DataFilesPage::profileChanged(const QString &previous, const QString ¤t)
|
||||
{
|
||||
// Prevent the deletion of the default profile
|
||||
if (current == "Default") {
|
||||
mDeleteProfileAction->setEnabled(false);
|
||||
} else {
|
||||
mDeleteProfileAction->setEnabled(true);
|
||||
}
|
||||
|
||||
if (!previous.isEmpty()) {
|
||||
writeConfig(previous);
|
||||
mLauncherConfig->sync();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
uncheckPlugins();
|
||||
|
@ -968,11 +1045,105 @@ void DataFilesPage::readConfig()
|
|||
|
||||
void DataFilesPage::writeConfig(QString profile)
|
||||
{
|
||||
// Don't overwrite the config if no plugins are found
|
||||
if (mPluginsModel->rowCount() < 1) {
|
||||
// Don't overwrite the config if no masters are found
|
||||
if (mMastersWidget->rowCount() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the OpenMW config
|
||||
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "openmw.cfg").string());
|
||||
QFile file(config);
|
||||
|
||||
if (!file.exists()) {
|
||||
config = QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string());
|
||||
}
|
||||
|
||||
// Open the config as a QFile
|
||||
file.setFileName(config);
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
// File cannot be opened or created
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QByteArray buffer;
|
||||
|
||||
// Remove all previous entries from config
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
if (!line.startsWith("master") &&
|
||||
!line.startsWith("plugin") &&
|
||||
!line.startsWith("data") &&
|
||||
!line.startsWith("data-local"))
|
||||
{
|
||||
buffer += line += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Now we write back the other config entries
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!buffer.isEmpty()) {
|
||||
file.write(buffer);
|
||||
}
|
||||
|
||||
QTextStream gameConfig(&file);
|
||||
|
||||
// First write the list of data dirs
|
||||
mCfgMgr.processPaths(mDataDirs);
|
||||
mCfgMgr.processPaths(mDataLocal);
|
||||
|
||||
QString path;
|
||||
|
||||
// data= directories
|
||||
for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) {
|
||||
path = QString::fromStdString(it->string());
|
||||
path.remove(QChar('\"'));
|
||||
|
||||
// Make sure the string is quoted when it contains spaces
|
||||
if (path.contains(" ")) {
|
||||
gameConfig << "data=\"" << path << "\"" << endl;
|
||||
} else {
|
||||
gameConfig << "data=" << path << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// data-local directory
|
||||
if (!mDataLocal.empty()) {
|
||||
path = QString::fromStdString(mDataLocal.front().string());
|
||||
path.remove(QChar('\"'));
|
||||
|
||||
if (path.contains(" ")) {
|
||||
gameConfig << "data-local=\"" << path << "\"" << endl;
|
||||
} else {
|
||||
gameConfig << "data-local=" << path << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (profile.isEmpty()) {
|
||||
profile = mProfilesComboBox->currentText();
|
||||
}
|
||||
|
@ -993,24 +1164,29 @@ void DataFilesPage::writeConfig(QString profile)
|
|||
mLauncherConfig->beginGroup(profile);
|
||||
mLauncherConfig->remove(""); // Clear the subgroup
|
||||
|
||||
// First write the masters to the config
|
||||
const QStringList masterList = selectedMasters();
|
||||
// Now write the masters to the configs
|
||||
const QStringList masters = selectedMasters();
|
||||
|
||||
// We don't use foreach because we need i
|
||||
for (int i = 0; i < masterList.size(); ++i) {
|
||||
const QString master = masterList.at(i);
|
||||
mLauncherConfig->setValue(QString("Master%0").arg(i), master);
|
||||
for (int i = 0; i < masters.size(); ++i) {
|
||||
const QString currentMaster = masters.at(i);
|
||||
|
||||
mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster);
|
||||
gameConfig << "master=" << currentMaster << endl;
|
||||
|
||||
}
|
||||
|
||||
// Now write all checked plugins
|
||||
// And finally write all checked plugins
|
||||
const QStringList plugins = checkedPlugins();
|
||||
|
||||
for (int i = 0; i < plugins.size(); ++i)
|
||||
{
|
||||
mLauncherConfig->setValue(QString("Plugin%1").arg(i), plugins.at(i));
|
||||
for (int i = 0; i < plugins.size(); ++i) {
|
||||
const QString currentPlugin = plugins.at(i);
|
||||
mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin);
|
||||
gameConfig << "plugin=" << currentPlugin << endl;
|
||||
}
|
||||
|
||||
file.close();
|
||||
mLauncherConfig->endGroup();
|
||||
mLauncherConfig->endGroup();
|
||||
|
||||
mLauncherConfig->sync();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <QWidget>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include <components/files/collections.hpp>
|
||||
|
||||
#include "combobox.hpp"
|
||||
|
||||
class QTableWidget;
|
||||
|
@ -19,24 +22,19 @@ class PluginsModel;
|
|||
class PluginsView;
|
||||
class ComboBox;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
|
||||
class DataFilesPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DataFilesPage(QWidget *parent = 0);
|
||||
DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0);
|
||||
|
||||
ComboBox *mProfilesComboBox;
|
||||
QSettings *mLauncherConfig;
|
||||
|
||||
const QStringList checkedPlugins();
|
||||
const QStringList selectedMasters();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
void writeConfig(QString profile = QString());
|
||||
|
||||
void setupDataFiles(const QStringList &paths, bool strict);
|
||||
|
||||
public slots:
|
||||
void masterSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void setCheckState(QModelIndex index);
|
||||
|
@ -81,11 +79,22 @@ private:
|
|||
QAction *mCheckAction;
|
||||
QAction *mUncheckAction;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
Files::PathContainer mDataDirs;
|
||||
Files::PathContainer mDataLocal;
|
||||
|
||||
QSettings *mLauncherConfig;
|
||||
|
||||
const QStringList checkedPlugins();
|
||||
const QStringList selectedMasters();
|
||||
|
||||
void addPlugins(const QModelIndex &index);
|
||||
void removePlugins(const QModelIndex &index);
|
||||
void uncheckPlugins();
|
||||
void createActions();
|
||||
|
||||
void setupDataFiles();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
void scrollToSelection();
|
||||
|
||||
};
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include <QtGui>
|
||||
|
||||
#include "graphicspage.hpp"
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
GraphicsPage::GraphicsPage(QWidget *parent) : QWidget(parent)
|
||||
GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mCfgMgr(cfg)
|
||||
{
|
||||
QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this);
|
||||
|
||||
|
@ -147,21 +150,21 @@ void GraphicsPage::createPages()
|
|||
|
||||
void GraphicsPage::setupConfig()
|
||||
{
|
||||
QString ogreCfg = mCfg.getOgreConfigPath().string().c_str();
|
||||
QString ogreCfg = mCfgMgr.getOgreConfigPath().string().c_str();
|
||||
QFile file(ogreCfg);
|
||||
mOgreConfig = new QSettings(ogreCfg, QSettings::IniFormat);
|
||||
}
|
||||
|
||||
void GraphicsPage::setupOgre()
|
||||
{
|
||||
QString pluginCfg = mCfg.getPluginsConfigPath().string().c_str();
|
||||
QString pluginCfg = mCfgMgr.getPluginsConfigPath().string().c_str();
|
||||
QFile file(pluginCfg);
|
||||
|
||||
// Create a log manager so we can surpress debug text to stdout/stderr
|
||||
Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager;
|
||||
logMgr->createLog((mCfg.getLogPath().string() + "/launcherOgre.log"), true, false, false);
|
||||
logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false);
|
||||
|
||||
QString ogreCfg = QString::fromStdString(mCfg.getOgreConfigPath().string());
|
||||
QString ogreCfg = QString::fromStdString(mCfgMgr.getOgreConfigPath().string());
|
||||
file.setFileName(ogreCfg);
|
||||
|
||||
//we need to check that the path to the configuration file exists before we
|
||||
|
@ -177,13 +180,17 @@ void GraphicsPage::setupOgre()
|
|||
Make sure you have write access to<br>%1<br><br>")).arg(configDir.path()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
#if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9)
|
||||
mOgre = new Ogre::Root("", file.fileName().toStdString(), "./launcherOgre.log");
|
||||
#else
|
||||
mOgre = new Ogre::Root(pluginCfg.toStdString(), file.fileName().toStdString(), "./launcherOgre.log");
|
||||
#endif
|
||||
}
|
||||
catch(Ogre::Exception &ex)
|
||||
{
|
||||
|
@ -200,10 +207,19 @@ void GraphicsPage::setupOgre()
|
|||
|
||||
qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError));
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
mGLPlugin = new Ogre::GLPlugin();
|
||||
mOgre->installPlugin(mGLPlugin);
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
mD3D9Plugin = new Ogre::D3D9Plugin();
|
||||
mOgre->installPlugin(mD3D9Plugin);
|
||||
#endif
|
||||
|
||||
// Get the available renderers and put them in the combobox
|
||||
const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers();
|
||||
|
||||
|
@ -234,7 +250,7 @@ void GraphicsPage::setupOgre()
|
|||
Please make sure the plugins.cfg file exists and contains a valid rendering plugin.<br>"));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -243,13 +259,7 @@ void GraphicsPage::setupOgre()
|
|||
if (mOpenGLRenderSystem) {
|
||||
mOGLRTTComboBox->addItems(getAvailableOptions(QString("RTT Preferred Mode"), mOpenGLRenderSystem));
|
||||
mOGLAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mOpenGLRenderSystem));
|
||||
|
||||
QStringList videoModes = getAvailableOptions(QString("Video Mode"), mOpenGLRenderSystem);
|
||||
// Remove extraneous spaces
|
||||
videoModes.replaceInStrings(QRegExp("\\s{2,}"), QString(" "));
|
||||
videoModes.replaceInStrings(QRegExp("^\\s"), QString());
|
||||
|
||||
mOGLResolutionComboBox->addItems(videoModes);
|
||||
mOGLResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mOpenGLRenderSystem));
|
||||
mOGLFrequencyComboBox->addItems(getAvailableOptions(QString("Display Frequency"), mOpenGLRenderSystem));
|
||||
}
|
||||
|
||||
|
@ -258,12 +268,7 @@ void GraphicsPage::setupOgre()
|
|||
mD3DRenderDeviceComboBox->addItems(getAvailableOptions(QString("Rendering Device"), mDirect3DRenderSystem));
|
||||
mD3DAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mDirect3DRenderSystem));
|
||||
mD3DFloatingPointComboBox->addItems(getAvailableOptions(QString("Floating-point mode"), mDirect3DRenderSystem));
|
||||
|
||||
QStringList videoModes = getAvailableOptions(QString("Video Mode"), mDirect3DRenderSystem);
|
||||
// Remove extraneous spaces
|
||||
videoModes.replaceInStrings(QRegExp("\\s{2,}"), QString(" "));
|
||||
videoModes.replaceInStrings(QRegExp("^\\s"), QString());
|
||||
mD3DResolutionComboBox->addItems(videoModes);
|
||||
mD3DResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mDirect3DRenderSystem));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +425,7 @@ void GraphicsPage::writeConfig()
|
|||
|
||||
qCritical("Error validating configuration");
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -446,7 +451,8 @@ void GraphicsPage::writeConfig()
|
|||
|
||||
qCritical("Error saving Ogre configuration, the error reported was:\n %s", qPrintable(ogreError));
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -478,7 +484,7 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
|
|||
{
|
||||
|
||||
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0)
|
||||
result << (*opt_it).c_str();
|
||||
result << QString::fromStdString((*opt_it).c_str()).simplified();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,21 +7,28 @@
|
|||
#include <OgreRenderSystem.h>
|
||||
#include <OgreConfigFile.h>
|
||||
#include <OgreConfigDialog.h>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
|
||||
// Static plugin headers
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
# include "OgreGLPlugin.h"
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
# include "OgreD3D9Plugin.h"
|
||||
#endif
|
||||
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QStackedWidget;
|
||||
class QSettings;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
|
||||
class GraphicsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphicsPage(QWidget *parent = 0);
|
||||
|
||||
QSettings *mOgreConfig;
|
||||
GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0);
|
||||
|
||||
void writeConfig();
|
||||
|
||||
|
@ -29,11 +36,16 @@ public slots:
|
|||
void rendererChanged(const QString &renderer);
|
||||
|
||||
private:
|
||||
Cfg::ConfigurationManager mCfg;
|
||||
Ogre::Root *mOgre;
|
||||
Ogre::RenderSystem *mSelectedRenderSystem;
|
||||
Ogre::RenderSystem *mOpenGLRenderSystem;
|
||||
Ogre::RenderSystem *mDirect3DRenderSystem;
|
||||
#ifdef ENABLE_PLUGIN_GL
|
||||
Ogre::GLPlugin* mGLPlugin;
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN_Direct3D9
|
||||
Ogre::D3D9Plugin* mD3D9Plugin;
|
||||
#endif
|
||||
|
||||
QComboBox *mRendererComboBox;
|
||||
|
||||
|
@ -59,6 +71,10 @@ private:
|
|||
QCheckBox *mD3DVSyncCheckBox;
|
||||
QCheckBox *mD3DFullScreenCheckBox;
|
||||
|
||||
QSettings *mOgreConfig;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
|
||||
QString getConfigValue(const QString &key, Ogre::RenderSystem *renderer);
|
||||
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "maindialog.hpp"
|
||||
|
||||
|
@ -17,17 +18,19 @@ int main(int argc, char *argv[])
|
|||
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());
|
||||
|
||||
// Load the stylesheet
|
||||
QFile file("./launcher.qss");
|
||||
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
app.setStyleSheet(styleSheet);
|
||||
|
||||
MainDialog dialog;
|
||||
return dialog.exec();
|
||||
|
||||
|
|
|
@ -45,6 +45,20 @@ MainDialog::MainDialog()
|
|||
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setMinimumSize(QSize(575, 575));
|
||||
|
||||
// Load the stylesheet
|
||||
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
|
||||
QFile file(config);
|
||||
|
||||
if (!file.exists()) {
|
||||
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string()));
|
||||
}
|
||||
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
qApp->setStyleSheet(styleSheet);
|
||||
file.close();
|
||||
|
||||
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(play()));
|
||||
|
||||
|
@ -85,116 +99,13 @@ void MainDialog::createIcons()
|
|||
|
||||
}
|
||||
|
||||
QStringList MainDialog::readConfig(const QString &fileName)
|
||||
{
|
||||
// We can't use QSettings directly because it
|
||||
// does not support multiple keys with the same name
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error opening OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not open %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(); // File cannot be opened or created
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QStringList dataDirs;
|
||||
QString dataLocal;
|
||||
|
||||
// Read the config line by line
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
|
||||
if (line.startsWith("data=")) {
|
||||
dataDirs.append(line.remove("data="));
|
||||
}
|
||||
|
||||
// Read the data-local key, if more than one are found only the last is used
|
||||
if (line.startsWith("data-local=")) {
|
||||
dataLocal = line.remove("data-local=");
|
||||
}
|
||||
|
||||
// Read fs-strict key
|
||||
if (line.startsWith("fs-strict=")) {
|
||||
QString value = line.remove("fs-strict=");
|
||||
|
||||
(value.toLower() == QLatin1String("true"))
|
||||
? mStrict = true
|
||||
: mStrict = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add the data-local= key to the end of the dataDirs for priority reasons
|
||||
if (!dataLocal.isEmpty()) {
|
||||
dataDirs.append(dataLocal);
|
||||
}
|
||||
|
||||
if (!dataDirs.isEmpty())
|
||||
{
|
||||
// Reset the global datadirs to the newly read entries
|
||||
// Else return the previous dataDirs because nothing was found in this file;
|
||||
mDataDirs = dataDirs;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return mDataDirs;
|
||||
}
|
||||
|
||||
void MainDialog::createPages()
|
||||
{
|
||||
mPlayPage = new PlayPage(this);
|
||||
mGraphicsPage = new GraphicsPage(this);
|
||||
mDataFilesPage = new DataFilesPage(this);
|
||||
mGraphicsPage = new GraphicsPage(mCfgMgr, this);
|
||||
mDataFilesPage = new DataFilesPage(mCfgMgr, this);
|
||||
|
||||
// Retrieve all data entries from the configs
|
||||
QStringList dataDirs;
|
||||
|
||||
// Global location
|
||||
QFile file(QString::fromStdString((mCfg.getGlobalConfigPath()/"openmw.cfg").string()));
|
||||
if (file.exists()) {
|
||||
dataDirs = readConfig(file.fileName());
|
||||
}
|
||||
|
||||
// User location
|
||||
file.setFileName(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string()));
|
||||
if (file.exists()) {
|
||||
dataDirs = readConfig(file.fileName());
|
||||
}
|
||||
|
||||
// Local location
|
||||
file.setFileName("./openmw.cfg");
|
||||
|
||||
if (file.exists()) {
|
||||
dataDirs = readConfig(file.fileName());
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
if (!dataDirs.isEmpty()) {
|
||||
// Now pass the datadirs on to the DataFilesPage
|
||||
mDataFilesPage->setupDataFiles(dataDirs, mStrict);
|
||||
} else {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error reading OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not read the location of the data files</b><br><br> \
|
||||
Please make sure OpenMW is correctly configured and try again.<br>"));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(); // No data or data-local entries in openmw.cfg
|
||||
}
|
||||
|
||||
// Set the combobox of the play page to imitate the comobox on the datafilespage
|
||||
// Set the combobox of the play page to imitate the combobox on the datafilespage
|
||||
mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model());
|
||||
mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex());
|
||||
|
||||
|
@ -246,14 +157,16 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
|||
void MainDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// Now write all config files
|
||||
writeConfig();
|
||||
mDataFilesPage->writeConfig();
|
||||
mGraphicsPage->writeConfig();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void MainDialog::play()
|
||||
{
|
||||
// First do a write of all the configs, just to be sure
|
||||
writeConfig();
|
||||
mDataFilesPage->writeConfig();
|
||||
mGraphicsPage->writeConfig();
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
QString game = "./openmw.exe";
|
||||
|
@ -313,75 +226,3 @@ void MainDialog::play()
|
|||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::writeConfig()
|
||||
{
|
||||
// Write the profiles
|
||||
mDataFilesPage->writeConfig();
|
||||
mDataFilesPage->mLauncherConfig->sync();
|
||||
|
||||
// Write the graphics settings
|
||||
mGraphicsPage->writeConfig();
|
||||
mGraphicsPage->mOgreConfig->sync();
|
||||
|
||||
QStringList dataFiles = mDataFilesPage->selectedMasters();
|
||||
dataFiles.append(mDataFilesPage->checkedPlugins());
|
||||
|
||||
// Open the config as a QFile
|
||||
QFile file(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string()));
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
// File cannot be opened or created
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QByteArray buffer;
|
||||
|
||||
// Remove all previous master/plugin entries from config
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
if (!line.contains("master") && !line.contains("plugin")) {
|
||||
buffer += line += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Now we write back the other config entries
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
}
|
||||
|
||||
file.write(buffer);
|
||||
|
||||
QTextStream out(&file);
|
||||
|
||||
// Write the list of game files to the config
|
||||
foreach (const QString ¤tFile, dataFiles) {
|
||||
|
||||
if (currentFile.endsWith(QString(".esm"), Qt::CaseInsensitive)) {
|
||||
out << "master=" << currentFile << endl;
|
||||
} else if (currentFile.endsWith(QString(".esp"), Qt::CaseInsensitive)) {
|
||||
out << "plugin=" << currentFile << endl;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <QDialog>
|
||||
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
|
@ -28,15 +28,11 @@ public slots:
|
|||
void play();
|
||||
void profileChanged(int index);
|
||||
|
||||
|
||||
private:
|
||||
void createIcons();
|
||||
void createPages();
|
||||
void writeConfig();
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
QStringList readConfig(const QString &fileName);
|
||||
|
||||
QListWidget *mIconWidget;
|
||||
QStackedWidget *mPagesWidget;
|
||||
|
||||
|
@ -44,10 +40,7 @@ private:
|
|||
GraphicsPage *mGraphicsPage;
|
||||
DataFilesPage *mDataFilesPage;
|
||||
|
||||
QStringList mDataDirs;
|
||||
bool mStrict;
|
||||
|
||||
Cfg::ConfigurationManager mCfg;
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
project(OpenMW)
|
||||
|
||||
# config file
|
||||
|
||||
configure_file ("${OpenMW_SOURCE_DIR}/config.hpp.cmake" "${OpenMW_SOURCE_DIR}/config.hpp")
|
||||
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.hpp.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/config.hpp")
|
||||
|
||||
# local files
|
||||
|
||||
set(GAME
|
||||
main.cpp
|
||||
engine.cpp
|
||||
)
|
||||
)
|
||||
set(GAME_HEADER
|
||||
engine.hpp
|
||||
config.hpp)
|
||||
config.hpp
|
||||
)
|
||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
renderingmanager debugging sky player npcs creatures objects renderinginterface water
|
||||
|
||||
renderingmanager debugging sky player renderinginterface water
|
||||
|
||||
animation npcanimation creatureanimation actors objects renderinginterface
|
||||
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -25,7 +27,7 @@ add_openmw_dir (mwinput
|
|||
|
||||
add_openmw_dir (mwgui
|
||||
layouts text_input widgets race class birth review window_manager console dialogue
|
||||
dialogue_history window_base stats_window messagebox
|
||||
dialogue_history window_base stats_window messagebox journalwindow charactercreation
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
@ -36,6 +38,7 @@ add_openmw_dir (mwscript
|
|||
locals scriptmanager compilercontext interpretercontext cellextensions miscextensions
|
||||
guiextensions soundextensions skyextensions statsextensions containerextensions
|
||||
aiextensions controlextensions extensions globalscripts ref dialogueextensions
|
||||
animationextensions
|
||||
)
|
||||
|
||||
add_openmw_dir (mwsound
|
||||
|
@ -44,8 +47,8 @@ add_openmw_dir (mwsound
|
|||
|
||||
add_openmw_dir (mwworld
|
||||
refdata world physicssystem scene environment globals class action nullaction actionteleport
|
||||
containerstore actiontalk actiontake containerstore manualref containerutil player cellfunctors
|
||||
cells localscripts
|
||||
containerstore actiontalk actiontake manualref player cellfunctors
|
||||
cells localscripts customdata weather inventorystore
|
||||
)
|
||||
|
||||
add_openmw_dir (mwclass
|
||||
|
@ -58,15 +61,22 @@ add_openmw_dir (mwmechanics
|
|||
)
|
||||
|
||||
# Main executable
|
||||
IF(OGRE_STATIC)
|
||||
IF(WIN32)
|
||||
ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL)
|
||||
set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES})
|
||||
ELSE(WIN32)
|
||||
ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL)
|
||||
set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES})
|
||||
ENDIF(WIN32)
|
||||
ENDIF(OGRE_STATIC)
|
||||
add_executable(openmw
|
||||
${OPENMW_LIBS} ${OPENMW_LIBS_HEADER}
|
||||
${CONPONENT_FILES}
|
||||
${COMPONENT_FILES}
|
||||
${OPENMW_FILES}
|
||||
${GAME} ${GAME_HEADER}
|
||||
${APPLE_BUNDLE_RESOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries (openmw components)
|
||||
)
|
||||
|
||||
# Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING
|
||||
# when we change the backend.
|
||||
|
@ -74,26 +84,23 @@ include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS})
|
|||
add_definitions(${SOUND_DEFINE})
|
||||
|
||||
target_link_libraries(openmw
|
||||
${OGRE_LIBRARIES}
|
||||
${OIS_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${OPENAL_LIBRARY}
|
||||
${SOUND_INPUT_LIBRARY}
|
||||
${BULLET_LIBRARIES}
|
||||
caelum
|
||||
MyGUIEngine
|
||||
MyGUIOgrePlatform
|
||||
${OGRE_LIBRARIES}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${OIS_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${OPENAL_LIBRARY}
|
||||
${SOUND_INPUT_LIBRARY}
|
||||
${BULLET_LIBRARIES}
|
||||
components
|
||||
MyGUIEngine
|
||||
MyGUIOgrePlatform
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
if(APPLE)
|
||||
find_library(CARBON_FRAMEWORK Carbon)
|
||||
target_link_libraries(openmw ${CARBON_FRAMEWORK})
|
||||
install(TARGETS openmw
|
||||
BUNDLE DESTINATION .
|
||||
RUNTIME DESTINATION ../MacOS
|
||||
COMPONENT Runtime)
|
||||
endif (APPLE)
|
||||
endif(APPLE)
|
||||
|
||||
if(DPKG_PROGRAM)
|
||||
INSTALL(TARGETS openmw RUNTIME DESTINATION games COMPONENT openmw)
|
||||
endif()
|
||||
endif(DPKG_PROGRAM)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
|
||||
#include <MyGUI_WidgetManager.h>
|
||||
|
||||
|
@ -17,8 +18,11 @@
|
|||
#include <components/esm_store/cell_store.hpp>
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
#include <components/esm/esm_reader.hpp>
|
||||
#include <components/files/path.hpp>
|
||||
#include <components/files/fixedpath.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include <components/nifbullet/bullet_nif_loader.hpp>
|
||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||
|
||||
#include "mwinput/inputmanager.hpp"
|
||||
|
||||
|
@ -33,8 +37,6 @@
|
|||
#include "mwsound/soundmanager.hpp"
|
||||
|
||||
#include "mwworld/world.hpp"
|
||||
#include "mwworld/ptr.hpp"
|
||||
#include "mwworld/environment.hpp"
|
||||
#include "mwworld/class.hpp"
|
||||
#include "mwworld/player.hpp"
|
||||
|
||||
|
@ -45,6 +47,7 @@
|
|||
|
||||
#include "mwmechanics/mechanicsmanager.hpp"
|
||||
|
||||
|
||||
void OMW::Engine::executeLocalScripts()
|
||||
{
|
||||
MWWorld::LocalScripts& localScripts = mEnvironment.mWorld->getLocalScripts();
|
||||
|
@ -99,6 +102,13 @@ void OMW::Engine::updateFocusReport (float duration)
|
|||
}
|
||||
}
|
||||
|
||||
void OMW::Engine::setAnimationVerbose(bool animverbose){
|
||||
if(animverbose){
|
||||
NifOgre::NIFLoader::getSingletonPtr()->setOutputAnimFiles(true);
|
||||
NifOgre::NIFLoader::getSingletonPtr()->setVerbosePath(mCfgMgr.getLogPath().string());
|
||||
}
|
||||
}
|
||||
|
||||
bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||
{
|
||||
try
|
||||
|
@ -108,15 +118,16 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
// sound
|
||||
if (mUseSound)
|
||||
{
|
||||
if (!mEnvironment.mSoundManager->isMusicPlaying())
|
||||
mEnvironment.mSoundManager->startRandomTitle();
|
||||
mEnvironment.mSoundManager->playPlaylist();
|
||||
|
||||
mEnvironment.mSoundManager->update (evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
// update GUI
|
||||
if(mShowFPS)
|
||||
mEnvironment.mWindowManager->wmSetFPS(mOgre->getFPS());
|
||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||
mEnvironment.mWindowManager->wmUpdateFps(window->getLastFPS(),
|
||||
window->getTriangleCount(),
|
||||
window->getBatchCount());
|
||||
|
||||
mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration);
|
||||
|
||||
|
@ -135,6 +146,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
mEnvironment.mWorld->advanceTime (
|
||||
mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600);
|
||||
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happend in local script
|
||||
mEnvironment.mWorld->markCellAsUnchanged();
|
||||
|
||||
|
@ -145,6 +157,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game)
|
||||
mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration);
|
||||
|
||||
// update world
|
||||
mEnvironment.mWorld->update (evt.timeSinceLastFrame);
|
||||
|
||||
// report focus object (for debugging)
|
||||
if (mReportFocus)
|
||||
updateFocusReport (mEnvironment.mFrameDuration);
|
||||
|
@ -157,10 +172,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
return true;
|
||||
}
|
||||
|
||||
OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager)
|
||||
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||
: mOgre (0)
|
||||
, mPhysicEngine (0)
|
||||
, mShowFPS (false)
|
||||
, mFpsLevel(0)
|
||||
, mDebug (false)
|
||||
, mVerboseScripts (false)
|
||||
, mNewGame (false)
|
||||
|
@ -170,7 +184,6 @@ OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager)
|
|||
, mFocusTDiff (0)
|
||||
, mScriptManager (0)
|
||||
, mScriptContext (0)
|
||||
, mGuiManager (0)
|
||||
, mFSStrict (false)
|
||||
, mCfgMgr(configurationManager)
|
||||
{
|
||||
|
@ -180,7 +193,6 @@ OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager)
|
|||
|
||||
OMW::Engine::~Engine()
|
||||
{
|
||||
delete mGuiManager;
|
||||
delete mEnvironment.mWorld;
|
||||
delete mEnvironment.mSoundManager;
|
||||
delete mEnvironment.mGlobalScripts;
|
||||
|
@ -189,7 +201,6 @@ OMW::Engine::~Engine()
|
|||
delete mEnvironment.mJournal;
|
||||
delete mScriptManager;
|
||||
delete mScriptContext;
|
||||
delete mPhysicEngine;
|
||||
delete mOgre;
|
||||
}
|
||||
|
||||
|
@ -198,15 +209,16 @@ OMW::Engine::~Engine()
|
|||
void OMW::Engine::loadBSA()
|
||||
{
|
||||
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
|
||||
|
||||
for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter)
|
||||
std::string dataDirectory;
|
||||
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
|
||||
{
|
||||
std::cout << "Adding " << iter->second.string() << std::endl;
|
||||
Bsa::addBSA (iter->second.string());
|
||||
}
|
||||
std::cout << "Adding " << iter->second.string() << std::endl;
|
||||
Bsa::addBSA(iter->second.string());
|
||||
|
||||
std::cout << "Data dir " << mDataDir.string() << std::endl;
|
||||
Bsa::addDir(mDataDir.string(), mFSStrict);
|
||||
dataDirectory = iter->second.parent_path().string();
|
||||
std::cout << "Data dir " << dataDirectory << std::endl;
|
||||
Bsa::addDir(dataDirectory, mFSStrict);
|
||||
}
|
||||
}
|
||||
|
||||
// add resources directory
|
||||
|
@ -227,9 +239,7 @@ void OMW::Engine::enableFSStrict(bool fsStrict)
|
|||
|
||||
void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs)
|
||||
{
|
||||
/// \todo remove mDataDir, once resources system can handle multiple directories
|
||||
assert (!dataDirs.empty());
|
||||
mDataDir = dataDirs.back();
|
||||
mDataDirs = dataDirs;
|
||||
mFileCollections = Files::Collections (dataDirs, !mFSStrict);
|
||||
}
|
||||
|
||||
|
@ -305,7 +315,7 @@ void OMW::Engine::go()
|
|||
}
|
||||
mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
|
||||
mCfgMgr.getOgreConfigPath().string(),
|
||||
mCfgMgr.getLogPath().string() + std::string("/"),
|
||||
mCfgMgr.getLogPath().string(),
|
||||
mCfgMgr.getPluginsConfigPath().string(), false);
|
||||
|
||||
// This has to be added BEFORE MyGUI is initialized, as it needs
|
||||
|
@ -321,31 +331,20 @@ void OMW::Engine::go()
|
|||
|
||||
loadBSA();
|
||||
|
||||
/// \todo move this into the physics manager
|
||||
// Create physics. shapeLoader is deleted by the physic engine
|
||||
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
|
||||
mPhysicEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
|
||||
|
||||
// Create the world
|
||||
mEnvironment.mWorld = new MWWorld::World (*mOgre, mPhysicEngine, mFileCollections, mMaster,
|
||||
mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster,
|
||||
mResDir, mNewGame, mEnvironment, mEncoding);
|
||||
|
||||
/// \todo move this into the GUI manager (a.k.a WindowManager)
|
||||
// Set up the GUI system
|
||||
mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false,
|
||||
mCfgMgr.getLogPath().string() + std::string("/"));
|
||||
|
||||
// Create window manager - this manages all the MW-specific GUI windows
|
||||
MWScript::registerExtensions (mExtensions);
|
||||
|
||||
mEnvironment.mWindowManager = new MWGui::WindowManager(mGuiManager->getGui(), mEnvironment,
|
||||
mExtensions, mShowFPS, mNewGame);
|
||||
mEnvironment.mWindowManager = new MWGui::WindowManager(mEnvironment,
|
||||
mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"));
|
||||
|
||||
// Create sound system
|
||||
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
|
||||
mOgre->getCamera(),
|
||||
mEnvironment.mWorld->getStore(),
|
||||
(mDataDir),
|
||||
mDataDirs,
|
||||
mUseSound, mFSStrict, mEnvironment);
|
||||
|
||||
// Create script system
|
||||
|
@ -393,7 +392,7 @@ void OMW::Engine::go()
|
|||
mOgre->getRoot()->addFrameListener (this);
|
||||
|
||||
// Play some good 'ol tunes
|
||||
mEnvironment.mSoundManager->startRandomTitle();
|
||||
mEnvironment.mSoundManager->playPlaylist(std::string("Explore"));
|
||||
|
||||
// scripts
|
||||
if (mCompileAll)
|
||||
|
@ -416,6 +415,9 @@ void OMW::Engine::go()
|
|||
|
||||
void OMW::Engine::activate()
|
||||
{
|
||||
if (mEnvironment.mWindowManager->getMode()!=MWGui::GM_Game)
|
||||
return;
|
||||
|
||||
std::string handle = mEnvironment.mWorld->getFacedHandle();
|
||||
|
||||
if (handle.empty())
|
||||
|
@ -449,6 +451,28 @@ void OMW::Engine::activate()
|
|||
}
|
||||
}
|
||||
|
||||
void OMW::Engine::screenshot()
|
||||
{
|
||||
// Count screenshots.
|
||||
int shotCount = 0;
|
||||
|
||||
const std::string screenshotPath = mCfgMgr.getUserPath().string();
|
||||
|
||||
// Find the first unused filename with a do-while
|
||||
std::ostringstream stream;
|
||||
do
|
||||
{
|
||||
// Reset the stream
|
||||
stream.str("");
|
||||
stream.clear();
|
||||
|
||||
stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << ".png";
|
||||
|
||||
} while (boost::filesystem::exists(stream.str()));
|
||||
|
||||
mOgre->screenshot(stream.str());
|
||||
}
|
||||
|
||||
void OMW::Engine::setCompileAll (bool all)
|
||||
{
|
||||
mCompileAll = all;
|
||||
|
@ -459,9 +483,9 @@ void OMW::Engine::setSoundUsage(bool soundUsage)
|
|||
mUseSound = soundUsage;
|
||||
}
|
||||
|
||||
void OMW::Engine::showFPS(bool showFps)
|
||||
void OMW::Engine::showFPS(int level)
|
||||
{
|
||||
mShowFPS = showFps;
|
||||
mFpsLevel = level;
|
||||
}
|
||||
|
||||
void OMW::Engine::setEncoding(const std::string& encoding)
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
|
||||
#include <OgreFrameListener.h>
|
||||
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
|
||||
#include "mwworld/environment.hpp"
|
||||
#include "mwworld/ptr.hpp"
|
||||
|
@ -54,19 +51,23 @@ namespace OEngine
|
|||
}
|
||||
}
|
||||
|
||||
namespace Files
|
||||
{
|
||||
struct ConfigurationManager;
|
||||
}
|
||||
|
||||
namespace OMW
|
||||
{
|
||||
/// \brief Main engine class, that brings together all the components of OpenMW
|
||||
class Engine : private Ogre::FrameListener
|
||||
{
|
||||
std::string mEncoding;
|
||||
boost::filesystem::path mDataDir;
|
||||
Files::PathContainer mDataDirs;
|
||||
boost::filesystem::path mResDir;
|
||||
OEngine::Render::OgreRenderer *mOgre;
|
||||
OEngine::Physic::PhysicEngine* mPhysicEngine;
|
||||
std::string mCellName;
|
||||
std::string mMaster;
|
||||
bool mShowFPS;
|
||||
int mFpsLevel;
|
||||
bool mDebug;
|
||||
bool mVerboseScripts;
|
||||
bool mNewGame;
|
||||
|
@ -80,7 +81,7 @@ namespace OMW
|
|||
MWScript::ScriptManager *mScriptManager;
|
||||
Compiler::Extensions mExtensions;
|
||||
Compiler::Context *mScriptContext;
|
||||
OEngine::GUI::MyGUIManager *mGuiManager;
|
||||
|
||||
|
||||
Files::Collections mFileCollections;
|
||||
bool mFSStrict;
|
||||
|
@ -104,7 +105,7 @@ namespace OMW
|
|||
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
|
||||
|
||||
public:
|
||||
Engine(Cfg::ConfigurationManager& configurationManager);
|
||||
Engine(Files::ConfigurationManager& configurationManager);
|
||||
virtual ~Engine();
|
||||
|
||||
/// Enable strict filesystem mode (do not fold case)
|
||||
|
@ -128,7 +129,7 @@ namespace OMW
|
|||
void addMaster(const std::string& master);
|
||||
|
||||
/// Enable fps counter
|
||||
void showFPS(bool showFps);
|
||||
void showFPS(int level);
|
||||
|
||||
/// Enable debug mode:
|
||||
/// - non-exclusive input
|
||||
|
@ -152,14 +153,19 @@ namespace OMW
|
|||
/// Activate the focussed object.
|
||||
void activate();
|
||||
|
||||
/// Write screenshot to file.
|
||||
void screenshot();
|
||||
|
||||
/// Compile all scripts (excludign dialogue scripts) at startup?
|
||||
void setCompileAll (bool all);
|
||||
|
||||
/// Font encoding
|
||||
void setEncoding(const std::string& encoding);
|
||||
|
||||
void setAnimationVerbose(bool animverbose);
|
||||
|
||||
private:
|
||||
Cfg::ConfigurationManager& mCfgMgr;
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <components/files/fileops.hpp>
|
||||
#include <components/files/path.hpp>
|
||||
#include <components/files/fixedpath.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include "engine.hpp"
|
||||
|
||||
|
@ -35,6 +35,23 @@
|
|||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* Workaround for problems with whitespaces in paths in older versions of Boost library
|
||||
*/
|
||||
#if (BOOST_VERSION <= 104600)
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<>
|
||||
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
|
||||
{
|
||||
return boost::filesystem::path(arg);
|
||||
}
|
||||
|
||||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
|
@ -46,7 +63,7 @@ using namespace std;
|
|||
* \retval true - Everything goes OK
|
||||
* \retval false - Error
|
||||
*/
|
||||
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::ConfigurationManager& cfgMgr)
|
||||
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::ConfigurationManager& cfgMgr)
|
||||
{
|
||||
// Create a local alias for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
|
@ -75,8 +92,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio
|
|||
("plugin", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
->multitoken(), "plugin file(s)")
|
||||
|
||||
("fps", boost::program_options::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "show fps counter")
|
||||
("fps", boost::program_options::value<int>()->implicit_value(1)
|
||||
->default_value(0), "fps counter detail (0 = off, 1 = fps counter, 2 = full detail)")
|
||||
|
||||
("anim-verbose", boost::program_options::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "output animation indices files")
|
||||
|
||||
("debug", boost::program_options::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "debug mode")
|
||||
|
@ -161,14 +181,19 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio
|
|||
std::string local(variables["data-local"].as<std::string>());
|
||||
if (!local.empty())
|
||||
{
|
||||
dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||
std::cout << "Ignoring data-local (currently not supported)" << std::endl;
|
||||
// dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||
}
|
||||
|
||||
if (dataDirs.empty())
|
||||
if (dataDirs.size()>1)
|
||||
{
|
||||
dataDirs.push_back(cfgMgr.getLocalDataPath());
|
||||
dataDirs.resize (1);
|
||||
std::cout << "Ignoring all but the first data path (multiple data paths currently not supported)"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
cfgMgr.processPaths(dataDirs);
|
||||
|
||||
engine.setDataDirs(dataDirs);
|
||||
|
||||
engine.setResourceDir(variables["resources"].as<std::string>());
|
||||
|
@ -200,12 +225,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio
|
|||
engine.setNewGame(variables["new-game"].as<bool>());
|
||||
|
||||
// other settings
|
||||
engine.showFPS(variables["fps"].as<bool>());
|
||||
engine.showFPS(variables["fps"].as<int>());
|
||||
engine.setDebugMode(variables["debug"].as<bool>());
|
||||
engine.setSoundUsage(!variables["nosound"].as<bool>());
|
||||
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
||||
engine.setCompileAll(variables["script-all"].as<bool>());
|
||||
engine.setReportFocus(variables["report-focus"].as<bool>());
|
||||
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -220,7 +246,7 @@ int main(int argc, char**argv)
|
|||
|
||||
try
|
||||
{
|
||||
Cfg::ConfigurationManager cfgMgr;
|
||||
Files::ConfigurationManager cfgMgr;
|
||||
OMW::Engine engine(cfgMgr);
|
||||
|
||||
if (parseOptions(argc, argv, engine, cfgMgr))
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +22,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -54,16 +56,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Apparatus::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.appas);
|
||||
}
|
||||
|
||||
std::string Apparatus::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Apparatus, MWWorld::RefData> *ref =
|
||||
|
@ -78,4 +76,14 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::Apparatus).name(), instance);
|
||||
}
|
||||
|
||||
std::string Apparatus::getUpSoundId (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
return std::string("Item Apparatus Up");
|
||||
}
|
||||
|
||||
std::string Apparatus::getDownSoundId (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
return std::string("Item Apparatus Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_APPARATUS_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,16 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,14 +2,21 @@
|
|||
#include "armor.hpp"
|
||||
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/loadgmst.hpp>
|
||||
|
||||
#include <components/esm_store/cell_store.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +27,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -53,6 +60,8 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
@ -70,12 +79,6 @@ namespace MWClass
|
|||
return ref->base->data.health;
|
||||
}
|
||||
|
||||
void Armor::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.armors);
|
||||
}
|
||||
|
||||
std::string Armor::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =
|
||||
|
@ -84,10 +87,105 @@ namespace MWClass
|
|||
return ref->base->script;
|
||||
}
|
||||
|
||||
std::pair<std::vector<int>, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Armor>();
|
||||
|
||||
std::vector<int> slots;
|
||||
|
||||
const int size = 11;
|
||||
|
||||
static const int sMapping[size][2] =
|
||||
{
|
||||
{ ESM::Armor::Helmet, MWWorld::InventoryStore::Slot_Helmet },
|
||||
{ ESM::Armor::Cuirass, MWWorld::InventoryStore::Slot_Cuirass },
|
||||
{ ESM::Armor::LPauldron, MWWorld::InventoryStore::Slot_LeftPauldron },
|
||||
{ ESM::Armor::RPauldron, MWWorld::InventoryStore::Slot_RightPauldron },
|
||||
{ ESM::Armor::Greaves, MWWorld::InventoryStore::Slot_Greaves },
|
||||
{ ESM::Armor::Boots, MWWorld::InventoryStore::Slot_Boots },
|
||||
{ ESM::Armor::LGauntlet, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||
{ ESM::Armor::RGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet },
|
||||
{ ESM::Armor::Shield, MWWorld::InventoryStore::Slot_CarriedLeft },
|
||||
{ ESM::Armor::LBracer, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||
{ ESM::Armor::RBracer, MWWorld::InventoryStore::Slot_RightGauntlet }
|
||||
};
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
if (sMapping[i][0]==ref->base->data.type)
|
||||
{
|
||||
slots.push_back (int (sMapping[i][1]));
|
||||
break;
|
||||
}
|
||||
|
||||
return std::make_pair (slots, false);
|
||||
}
|
||||
|
||||
int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Armor>();
|
||||
|
||||
std::string typeGmst;
|
||||
|
||||
switch (ref->base->data.type)
|
||||
{
|
||||
case ESM::Armor::Helmet: typeGmst = "iHelmWeight"; break;
|
||||
case ESM::Armor::Cuirass: typeGmst = "iCuirassWeight"; break;
|
||||
case ESM::Armor::LPauldron:
|
||||
case ESM::Armor::RPauldron: typeGmst = "iPauldronWeight"; break;
|
||||
case ESM::Armor::Greaves: typeGmst = "iGreavesWeight"; break;
|
||||
case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break;
|
||||
case ESM::Armor::LGauntlet:
|
||||
case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break;
|
||||
/// \todo how to determine if shield light, medium or heavy?
|
||||
// case ESM::Armor::Shield:
|
||||
case ESM::Armor::LBracer:
|
||||
case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break;
|
||||
}
|
||||
|
||||
if (typeGmst.empty())
|
||||
return -1;
|
||||
|
||||
float iWeight = environment.mWorld->getStore().gameSettings.find (typeGmst)->i;
|
||||
|
||||
if (iWeight * environment.mWorld->getStore().gameSettings.find ("fLightMaxMod")->f>=
|
||||
ref->base->data.weight)
|
||||
return ESM::Skill::LightArmor;
|
||||
|
||||
if (iWeight * environment.mWorld->getStore().gameSettings.find ("fMedMaxMod")->f>=
|
||||
ref->base->data.weight)
|
||||
return ESM::Skill::MediumArmor;
|
||||
|
||||
return ESM::Skill::HeavyArmor;
|
||||
}
|
||||
|
||||
void Armor::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Armor);
|
||||
|
||||
registerClass (typeid (ESM::Armor).name(), instance);
|
||||
}
|
||||
|
||||
std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
int es = getEquipmentSkill(ptr, environment);
|
||||
if (es == ESM::Skill::LightArmor)
|
||||
return std::string("Item Armor Light Up");
|
||||
else if (es == ESM::Skill::MediumArmor)
|
||||
return std::string("Item Armor Medium Up");
|
||||
else
|
||||
return std::string("Item Armor Heavy Up");
|
||||
}
|
||||
|
||||
std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
int es = getEquipmentSkill(ptr, environment);
|
||||
if (es == ESM::Skill::LightArmor)
|
||||
return std::string("Item Armor Light Down");
|
||||
else if (es == ESM::Skill::MediumArmor)
|
||||
return std::string("Item Armor Medium Down");
|
||||
else
|
||||
return std::string("Item Armor Heavy Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_ARMOR_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -29,14 +28,25 @@ namespace MWClass
|
|||
virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const;
|
||||
///< Return item max health or throw an exception, if class does not have item health
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||
/// stay stacked when equipped?
|
||||
|
||||
virtual int getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Environment& environment) const;
|
||||
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||
/// no such skill.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +22,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -56,16 +58,12 @@ namespace MWClass
|
|||
{
|
||||
// TODO implement reading
|
||||
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Book::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.books);
|
||||
}
|
||||
|
||||
std::string Book::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Book, MWWorld::RefData> *ref =
|
||||
|
@ -80,4 +78,14 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::Book).name(), instance);
|
||||
}
|
||||
|
||||
std::string Book::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Book Up");
|
||||
}
|
||||
|
||||
std::string Book::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Book Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_BOOK_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,16 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +23,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -54,16 +57,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Clothing::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.clothes);
|
||||
}
|
||||
|
||||
std::string Clothing::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||
|
@ -72,10 +71,86 @@ namespace MWClass
|
|||
return ref->base->script;
|
||||
}
|
||||
|
||||
std::pair<std::vector<int>, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Clothing>();
|
||||
|
||||
std::vector<int> slots;
|
||||
|
||||
if (ref->base->data.type==ESM::Clothing::Ring)
|
||||
{
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_LeftRing));
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_RightRing));
|
||||
}
|
||||
else
|
||||
{
|
||||
const int size = 9;
|
||||
|
||||
static const int sMapping[size][2] =
|
||||
{
|
||||
{ ESM::Clothing::Shirt, MWWorld::InventoryStore::Slot_Cuirass },
|
||||
{ ESM::Clothing::Belt, MWWorld::InventoryStore::Slot_Belt },
|
||||
{ ESM::Clothing::Robe, MWWorld::InventoryStore::Slot_Robe },
|
||||
{ ESM::Clothing::Pants, MWWorld::InventoryStore::Slot_Pants },
|
||||
{ ESM::Clothing::Shoes, MWWorld::InventoryStore::Slot_Boots },
|
||||
{ ESM::Clothing::LGlove, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||
{ ESM::Clothing::RGlove, MWWorld::InventoryStore::Slot_RightGauntlet },
|
||||
{ ESM::Clothing::Skirt, MWWorld::InventoryStore::Slot_Skirt },
|
||||
{ ESM::Clothing::Amulet, MWWorld::InventoryStore::Slot_Amulet }
|
||||
};
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
if (sMapping[i][0]==ref->base->data.type)
|
||||
{
|
||||
slots.push_back (int (sMapping[i][1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair (slots, false);
|
||||
}
|
||||
|
||||
int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Clothing>();
|
||||
|
||||
if (ref->base->data.type==ESM::Clothing::Shoes)
|
||||
return ESM::Skill::Unarmored;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Clothing::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Clothing);
|
||||
|
||||
registerClass (typeid (ESM::Clothing).name(), instance);
|
||||
}
|
||||
|
||||
std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Clothing>();
|
||||
|
||||
if (ref->base->data.type == 8)
|
||||
{
|
||||
return std::string("Item Ring Up");
|
||||
}
|
||||
return std::string("Item Clothes Up");
|
||||
}
|
||||
|
||||
std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Clothing>();
|
||||
|
||||
if (ref->base->data.type == 8)
|
||||
{
|
||||
return std::string("Item Ring Down");
|
||||
}
|
||||
return std::string("Item Clothes Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_CLOTHING_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,25 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||
/// stay stacked when equipped?
|
||||
|
||||
virtual int getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Environment& environment) const;
|
||||
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||
/// no such skill.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,45 @@
|
|||
#include <components/esm_store/cell_store.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWWorld::ContainerStore mContainerStore;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void Container::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
|
||||
// \todo add initial container content
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
}
|
||||
}
|
||||
|
||||
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Container, MWWorld::RefData> *ref =
|
||||
|
@ -16,7 +52,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -39,6 +75,38 @@ namespace MWClass
|
|||
|
||||
}
|
||||
|
||||
boost::shared_ptr<MWWorld::Action> Container::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
const std::string lockedSound = "LockedChest";
|
||||
const std::string trapActivationSound = "Disarm Trap Fail";
|
||||
|
||||
if (ptr.getCellRef().lockLevel>0)
|
||||
{
|
||||
// TODO check for key
|
||||
std::cout << "Locked container" << std::endl;
|
||||
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false);
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unlocked container" << std::endl;
|
||||
if(ptr.getCellRef().trap.empty())
|
||||
{
|
||||
// Not trapped, Inventory GUI goes here
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Trap activation goes here
|
||||
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
||||
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0, false);
|
||||
ptr.getCellRef().trap = "";
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Container::getName (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Container, MWWorld::RefData> *ref =
|
||||
|
@ -47,20 +115,12 @@ namespace MWClass
|
|||
return ref->base->name;
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& Container::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
{
|
||||
if (!ptr.getRefData().getContainerStore().get())
|
||||
{
|
||||
boost::shared_ptr<MWWorld::ContainerStore<MWWorld::RefData> > store (
|
||||
new MWWorld::ContainerStore<MWWorld::RefData>);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
// TODO add initial content
|
||||
|
||||
ptr.getRefData().getContainerStore() = store;
|
||||
}
|
||||
|
||||
return *ptr.getRefData().getContainerStore();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
}
|
||||
|
||||
std::string Container::getScript (const MWWorld::Ptr& ptr) const
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
#define GAME_MWCLASS_CONTAINER_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class Container : public MWWorld::Class
|
||||
{
|
||||
void ensureCustomData (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
public:
|
||||
|
||||
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
|
||||
|
@ -19,8 +20,11 @@ namespace MWClass
|
|||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
|
||||
virtual MWWorld::ContainerStore<MWWorld::RefData>& getContainerStore (
|
||||
const MWWorld::Ptr& ptr) const;
|
||||
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const;
|
||||
///< Return container store
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef GAME_MWCLASS_CONTAINERUTIL_H
|
||||
#define GAME_MWCLASS_CONTAINERUTIL_H
|
||||
|
||||
#include <components/esm_store/cell_store.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
template<typename T>
|
||||
void insertIntoContainerStore (const MWWorld::Ptr& ptr,
|
||||
ESMS::CellRefList<T, MWWorld::RefData>& containerStore)
|
||||
{
|
||||
if (!ptr.isEmpty())
|
||||
{
|
||||
// TODO check stacking
|
||||
|
||||
ESMS::LiveCellRef<T, MWWorld::RefData> cellRef(ptr.getCellRef(), ptr.get<T>()->base);
|
||||
cellRef.mData = ptr.getRefData();
|
||||
|
||||
containerStore.list.push_back (cellRef);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4,16 +4,62 @@
|
|||
#include <components/esm/loadcrea.hpp>
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::CreatureStats mCreatureStats;
|
||||
MWWorld::ContainerStore mContainerStore;
|
||||
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void Creature::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
// creature stats
|
||||
data->mCreatureStats.mAttributes[0].set (ref->base->data.strength);
|
||||
data->mCreatureStats.mAttributes[1].set (ref->base->data.intelligence);
|
||||
data->mCreatureStats.mAttributes[2].set (ref->base->data.willpower);
|
||||
data->mCreatureStats.mAttributes[3].set (ref->base->data.agility);
|
||||
data->mCreatureStats.mAttributes[4].set (ref->base->data.speed);
|
||||
data->mCreatureStats.mAttributes[5].set (ref->base->data.endurance);
|
||||
data->mCreatureStats.mAttributes[6].set (ref->base->data.personality);
|
||||
data->mCreatureStats.mAttributes[7].set (ref->base->data.luck);
|
||||
data->mCreatureStats.mDynamic[0].set (ref->base->data.health);
|
||||
data->mCreatureStats.mDynamic[1].set (ref->base->data.mana);
|
||||
data->mCreatureStats.mDynamic[2].set (ref->base->data.fatigue);
|
||||
|
||||
data->mCreatureStats.mLevel = ref->base->data.level;
|
||||
|
||||
// \todo add initial container content
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
}
|
||||
}
|
||||
|
||||
std::string Creature::getId (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref =
|
||||
|
@ -24,24 +70,12 @@ namespace MWClass
|
|||
|
||||
void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
/*
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Creatures& creatures = renderingInterface.getCreatures();
|
||||
//creatures.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
//creatures.insertMesh(ptr, "meshes\\" + model);
|
||||
}*/
|
||||
MWRender::Actors& actors = renderingInterface.getActors();
|
||||
actors.insertCreature(ptr);
|
||||
}
|
||||
|
||||
void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
|
||||
{
|
||||
/*
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
|
@ -50,8 +84,7 @@ namespace MWClass
|
|||
assert (ref->base != NULL);
|
||||
if(!model.empty()){
|
||||
physics.insertActorPhysics(ptr, "meshes\\" + model);
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const
|
||||
|
@ -74,31 +107,9 @@ namespace MWClass
|
|||
|
||||
MWMechanics::CreatureStats& Creature::getCreatureStats (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCreatureStats().get())
|
||||
{
|
||||
boost::shared_ptr<MWMechanics::CreatureStats> stats (
|
||||
new MWMechanics::CreatureStats);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
stats->mAttributes[0].set (ref->base->data.strength);
|
||||
stats->mAttributes[1].set (ref->base->data.intelligence);
|
||||
stats->mAttributes[2].set (ref->base->data.willpower);
|
||||
stats->mAttributes[3].set (ref->base->data.agility);
|
||||
stats->mAttributes[4].set (ref->base->data.speed);
|
||||
stats->mAttributes[5].set (ref->base->data.endurance);
|
||||
stats->mAttributes[6].set (ref->base->data.personality);
|
||||
stats->mAttributes[7].set (ref->base->data.luck);
|
||||
stats->mDynamic[0].set (ref->base->data.health);
|
||||
stats->mDynamic[1].set (ref->base->data.mana);
|
||||
stats->mDynamic[2].set (ref->base->data.fatigue);
|
||||
|
||||
stats->mLevel = ref->base->data.level;
|
||||
|
||||
ptr.getRefData().getCreatureStats() = stats;
|
||||
}
|
||||
|
||||
return *ptr.getRefData().getCreatureStats();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
|
||||
}
|
||||
|
||||
boost::shared_ptr<MWWorld::Action> Creature::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -107,20 +118,12 @@ namespace MWClass
|
|||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& Creature::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
{
|
||||
if (!ptr.getRefData().getContainerStore().get())
|
||||
{
|
||||
boost::shared_ptr<MWWorld::ContainerStore<MWWorld::RefData> > store (
|
||||
new MWWorld::ContainerStore<MWWorld::RefData>);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
// TODO add initial content
|
||||
|
||||
ptr.getRefData().getContainerStore() = store;
|
||||
}
|
||||
|
||||
return *ptr.getRefData().getContainerStore();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
}
|
||||
|
||||
std::string Creature::getScript (const MWWorld::Ptr& ptr) const
|
||||
|
|
|
@ -2,12 +2,16 @@
|
|||
#define GAME_MWCLASS_CREATURE_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/creatures.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
#include "../mwrender/actors.hpp"
|
||||
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class Creature : public MWWorld::Class
|
||||
{
|
||||
void ensureCustomData (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
public:
|
||||
|
||||
virtual std::string getId (const MWWorld::Ptr& ptr) const;
|
||||
|
@ -35,7 +39,7 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual MWWorld::ContainerStore<MWWorld::RefData>& getContainerStore (
|
||||
virtual MWWorld::ContainerStore& getContainerStore (
|
||||
const MWWorld::Ptr& ptr) const;
|
||||
///< Return container store
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -39,13 +39,11 @@ namespace MWClass
|
|||
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Door>();
|
||||
|
||||
|
||||
const std::string &model = ref->base->model;
|
||||
assert (ref->base != NULL);
|
||||
if(!model.empty()){
|
||||
physics.insertObjectPhysics(ptr, "meshes\\" + model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string Door::getName (const MWWorld::Ptr& ptr) const
|
||||
|
@ -65,15 +63,28 @@ namespace MWClass
|
|||
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Door>();
|
||||
|
||||
const std::string &openSound = ref->base->openSound;
|
||||
//const std::string &closeSound = ref->base->closeSound;
|
||||
const std::string lockedSound = "LockedDoor";
|
||||
const std::string trapActivationSound = "Disarm Trap Fail";
|
||||
|
||||
if (ptr.getCellRef().lockLevel>0)
|
||||
{
|
||||
// TODO check for key
|
||||
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
|
||||
std::cout << "Locked!" << std::endl;
|
||||
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false);
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
|
||||
// TODO check trap
|
||||
if(!ptr.getCellRef().trap.empty())
|
||||
{
|
||||
// Trap activation
|
||||
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
|
||||
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0, false);
|
||||
ptr.getCellRef().trap = "";
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
|
||||
if (ref->ref.teleport)
|
||||
{
|
||||
|
@ -81,12 +92,14 @@ namespace MWClass
|
|||
if (environment.mWorld->getPlayer().getPlayer()==actor)
|
||||
{
|
||||
// the player is using the door
|
||||
// The reason this is not 3D is that it would get interrupted when you teleport
|
||||
environment.mSoundManager->playSound(openSound, 1.0, 1.0);
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest));
|
||||
}
|
||||
else
|
||||
{
|
||||
// another NPC or a create is using the door
|
||||
// another NPC or a creature is using the door
|
||||
// TODO return action for teleporting other NPC/creature
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
|
@ -95,6 +108,9 @@ namespace MWClass
|
|||
{
|
||||
// animated door
|
||||
// TODO return action for rotating the door
|
||||
|
||||
// This is a little pointless, but helps with testing
|
||||
environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0, false);
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_DOOR_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +22,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -34,14 +36,11 @@ namespace MWClass
|
|||
ESMS::LiveCellRef<ESM::Ingredient, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Ingredient>();
|
||||
|
||||
|
||||
|
||||
const std::string &model = ref->base->model;
|
||||
assert (ref->base != NULL);
|
||||
if(!model.empty()){
|
||||
physics.insertObjectPhysics(ptr, "meshes\\" + model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string Ingredient::getName (const MWWorld::Ptr& ptr) const
|
||||
|
@ -55,16 +54,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Ingredient::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.ingreds);
|
||||
}
|
||||
|
||||
std::string Ingredient::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Ingredient, MWWorld::RefData> *ref =
|
||||
|
@ -79,4 +74,14 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::Ingredient).name(), instance);
|
||||
}
|
||||
|
||||
std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Ingredient Up");
|
||||
}
|
||||
|
||||
std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Ingredient Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_INGREDIENT_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,16 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,19 +24,19 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, "meshes\\" + model);
|
||||
const int color = ref->base->data.color;
|
||||
const float r = ((color >> 0) & 0xFF) / 255.0f;
|
||||
const float g = ((color >> 8) & 0xFF) / 255.0f;
|
||||
const float b = ((color >> 16) & 0xFF) / 255.0f;
|
||||
const float radius = float (ref->base->data.radius);
|
||||
objects.insertLight (ptr, r, g, b, radius);
|
||||
}
|
||||
|
||||
const int color = ref->base->data.color;
|
||||
const float r = ((color >> 0) & 0xFF) / 255.0f;
|
||||
const float g = ((color >> 8) & 0xFF) / 255.0f;
|
||||
const float b = ((color >> 16) & 0xFF) / 255.0f;
|
||||
const float radius = float (ref->base->data.radius);
|
||||
objects.insertLight (ptr, r, g, b, radius);
|
||||
}
|
||||
|
||||
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
|
||||
|
@ -43,13 +44,12 @@ namespace MWClass
|
|||
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Light>();
|
||||
|
||||
|
||||
const std::string &model = ref->base->model;
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
if(!model.empty()){
|
||||
physics.insertObjectPhysics(ptr, "meshes\\" + model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Light::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const
|
||||
|
@ -83,16 +83,12 @@ namespace MWClass
|
|||
if (!(ref->base->data.flags & ESM::Light::Carry))
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Light::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.lights);
|
||||
}
|
||||
|
||||
std::string Light::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
|
||||
|
@ -101,10 +97,33 @@ namespace MWClass
|
|||
return ref->base->script;
|
||||
}
|
||||
|
||||
std::pair<std::vector<int>, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Light>();
|
||||
|
||||
std::vector<int> slots;
|
||||
|
||||
if (ref->base->data.flags & ESM::Light::Carry)
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedLeft));
|
||||
|
||||
return std::make_pair (slots, false);
|
||||
}
|
||||
|
||||
void Light::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Light);
|
||||
|
||||
registerClass (typeid (ESM::Light).name(), instance);
|
||||
}
|
||||
|
||||
std::string Light::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Misc Up");
|
||||
}
|
||||
|
||||
std::string Light::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Misc Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_LIGHT_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -28,14 +27,20 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||
/// stay stacked when equipped?
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,12 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -19,7 +23,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -54,16 +58,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Lockpick::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.lockpicks);
|
||||
}
|
||||
|
||||
std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Tool, MWWorld::RefData> *ref =
|
||||
|
@ -72,10 +72,29 @@ namespace MWClass
|
|||
return ref->base->script;
|
||||
}
|
||||
|
||||
std::pair<std::vector<int>, bool> Lockpick::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
std::vector<int> slots;
|
||||
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||
|
||||
return std::make_pair (slots, false);
|
||||
}
|
||||
|
||||
void Lockpick::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Lockpick);
|
||||
|
||||
registerClass (typeid (ESM::Tool).name(), instance);
|
||||
}
|
||||
|
||||
std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Lockpick Up");
|
||||
}
|
||||
|
||||
std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Lockpick Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_LOCKPICK_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,20 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||
/// stay stacked when equipped?
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -19,7 +22,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -53,16 +56,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Miscellaneous::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.miscItems);
|
||||
}
|
||||
|
||||
std::string Miscellaneous::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =
|
||||
|
@ -77,4 +76,28 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::Miscellaneous).name(), instance);
|
||||
}
|
||||
|
||||
std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Miscellaneous>();
|
||||
|
||||
if (ref->base->name =="Gold")
|
||||
{
|
||||
return std::string("Item Gold Up");
|
||||
}
|
||||
return std::string("Item Misc Up");
|
||||
}
|
||||
|
||||
std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Miscellaneous>();
|
||||
|
||||
if (ref->base->name =="Gold")
|
||||
{
|
||||
return std::string("Item Gold Down");
|
||||
}
|
||||
return std::string("Item Misc Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_MISC_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,16 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,88 @@
|
|||
|
||||
#include "npc.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
#include <OgreSceneNode.h>
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
const Ogre::Radian kOgrePi (Ogre::Math::PI);
|
||||
const Ogre::Radian kOgrePiOverTwo (Ogre::Math::PI / Ogre::Real(2.0));
|
||||
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::NpcStats mNpcStats;
|
||||
MWMechanics::CreatureStats mCreatureStats;
|
||||
MWMechanics::Movement mMovement;
|
||||
MWWorld::InventoryStore mInventoryStore;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref = ptr.get<ESM::NPC>();
|
||||
|
||||
// NPC stats
|
||||
if (!ref->base->faction.empty())
|
||||
{
|
||||
// TODO research how initial rank is stored. The information in loadnpc.hpp are at
|
||||
// best very unclear.
|
||||
data->mNpcStats.mFactionRank[ref->base->faction] = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]);
|
||||
|
||||
// creature stats
|
||||
data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength);
|
||||
data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence);
|
||||
data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower);
|
||||
data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility);
|
||||
data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed);
|
||||
data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance);
|
||||
data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality);
|
||||
data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck);
|
||||
data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health);
|
||||
data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana);
|
||||
data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue);
|
||||
|
||||
data->mCreatureStats.mLevel = ref->base->npdt52.level;
|
||||
|
||||
// \todo add initial container content
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
}
|
||||
}
|
||||
|
||||
std::string Npc::getId (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
|
||||
|
@ -32,34 +93,28 @@ namespace MWClass
|
|||
|
||||
void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
/*
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::NPC>();
|
||||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Npcs& npcs = renderingInterface.getNPCs();
|
||||
//npcs.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
//npcs.insertMesh(ptr, "meshes\\" + model);
|
||||
}*/
|
||||
renderingInterface.getActors().insertNPC(ptr);
|
||||
}
|
||||
|
||||
void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
|
||||
{
|
||||
|
||||
/*
|
||||
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::NPC>();
|
||||
|
||||
|
||||
const std::string &model = ref->base->model;
|
||||
assert (ref->base != NULL);
|
||||
if(!model.empty()){
|
||||
physics.insertActorPhysics(ptr, "meshes\\" + model);
|
||||
}*/
|
||||
std::string headID = ref->base->head;
|
||||
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
|
||||
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";
|
||||
|
||||
|
||||
std::string smodel = "meshes\\base_anim.nif";
|
||||
if(beast)
|
||||
smodel = "meshes\\base_animkna.nif";
|
||||
physics.insertActorPhysics(ptr, smodel);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -83,56 +138,16 @@ namespace MWClass
|
|||
|
||||
MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCreatureStats().get())
|
||||
{
|
||||
boost::shared_ptr<MWMechanics::CreatureStats> stats (
|
||||
new MWMechanics::CreatureStats);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref = ptr.get<ESM::NPC>();
|
||||
|
||||
stats->mAttributes[0].set (ref->base->npdt52.strength);
|
||||
stats->mAttributes[1].set (ref->base->npdt52.intelligence);
|
||||
stats->mAttributes[2].set (ref->base->npdt52.willpower);
|
||||
stats->mAttributes[3].set (ref->base->npdt52.agility);
|
||||
stats->mAttributes[4].set (ref->base->npdt52.speed);
|
||||
stats->mAttributes[5].set (ref->base->npdt52.endurance);
|
||||
stats->mAttributes[6].set (ref->base->npdt52.personality);
|
||||
stats->mAttributes[7].set (ref->base->npdt52.luck);
|
||||
stats->mDynamic[0].set (ref->base->npdt52.health);
|
||||
stats->mDynamic[1].set (ref->base->npdt52.mana);
|
||||
stats->mDynamic[2].set (ref->base->npdt52.fatigue);
|
||||
|
||||
stats->mLevel = ref->base->npdt52.level;
|
||||
|
||||
ptr.getRefData().getCreatureStats() = stats;
|
||||
}
|
||||
|
||||
return *ptr.getRefData().getCreatureStats();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
|
||||
}
|
||||
|
||||
MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getNpcStats().get())
|
||||
{
|
||||
boost::shared_ptr<MWMechanics::NpcStats> stats (
|
||||
new MWMechanics::NpcStats);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref = ptr.get<ESM::NPC>();
|
||||
|
||||
if (!ref->base->faction.empty())
|
||||
{
|
||||
// TODO research how initial rank is stored. The information in loadnpc.hpp are at
|
||||
// best very unclear.
|
||||
stats->mFactionRank[ref->base->faction] = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
stats->mSkill[i].setBase (ref->base->npdt52.skills[i]);
|
||||
|
||||
ptr.getRefData().getNpcStats() = stats;
|
||||
}
|
||||
|
||||
return *ptr.getRefData().getNpcStats();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
|
||||
}
|
||||
|
||||
boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -141,20 +156,20 @@ namespace MWClass
|
|||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
{
|
||||
if (!ptr.getRefData().getContainerStore().get())
|
||||
{
|
||||
boost::shared_ptr<MWWorld::ContainerStore<MWWorld::RefData> > store (
|
||||
new MWWorld::ContainerStore<MWWorld::RefData>);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
// TODO add initial content
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||
}
|
||||
|
||||
ptr.getRefData().getContainerStore() = store;
|
||||
}
|
||||
MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return *ptr.getRefData().getContainerStore();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||
}
|
||||
|
||||
std::string Npc::getScript (const MWWorld::Ptr& ptr) const
|
||||
|
@ -245,29 +260,20 @@ namespace MWClass
|
|||
|
||||
MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getMovement().get())
|
||||
{
|
||||
boost::shared_ptr<MWMechanics::Movement> movement (
|
||||
new MWMechanics::Movement);
|
||||
ensureCustomData (ptr);
|
||||
|
||||
ptr.getRefData().getMovement() = movement;
|
||||
}
|
||||
|
||||
return *ptr.getRefData().getMovement();
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
|
||||
}
|
||||
|
||||
Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
Ogre::Vector3 vector (0, 0, 0);
|
||||
|
||||
if (ptr.getRefData().getMovement().get())
|
||||
{
|
||||
vector.x = - ptr.getRefData().getMovement()->mLeftRight * 200;
|
||||
vector.y = ptr.getRefData().getMovement()->mForwardBackward * 200;
|
||||
vector.x = - getMovementSettings (ptr).mLeftRight * 200;
|
||||
vector.y = getMovementSettings (ptr).mForwardBackward * 200;
|
||||
|
||||
if (getStance (ptr, Run, false))
|
||||
vector *= 2;
|
||||
}
|
||||
if (getStance (ptr, Run, false))
|
||||
vector *= 2;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
#define GAME_MWCLASS_NPC_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/npcs.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class Npc : public MWWorld::Class
|
||||
{
|
||||
void ensureCustomData (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
public:
|
||||
|
||||
virtual std::string getId (const MWWorld::Ptr& ptr) const;
|
||||
|
@ -34,10 +35,12 @@ namespace MWClass
|
|||
virtual MWMechanics::NpcStats& getNpcStats (const MWWorld::Ptr& ptr) const;
|
||||
///< Return NPC stats
|
||||
|
||||
virtual MWWorld::ContainerStore<MWWorld::RefData>& getContainerStore (
|
||||
const MWWorld::Ptr& ptr) const;
|
||||
virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const;
|
||||
///< Return container store
|
||||
|
||||
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
|
||||
///< Return inventory store
|
||||
|
||||
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +22,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -54,16 +56,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Potion::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.potions);
|
||||
}
|
||||
|
||||
std::string Potion::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Potion, MWWorld::RefData> *ref =
|
||||
|
@ -78,4 +76,14 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::Potion).name(), instance);
|
||||
}
|
||||
|
||||
std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Potion Up");
|
||||
}
|
||||
|
||||
std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Potion Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_POTION_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,16 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
|
@ -20,7 +23,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -54,16 +57,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Probe::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.probes);
|
||||
}
|
||||
|
||||
std::string Probe::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Probe, MWWorld::RefData> *ref =
|
||||
|
@ -72,10 +71,29 @@ namespace MWClass
|
|||
return ref->base->script;
|
||||
}
|
||||
|
||||
std::pair<std::vector<int>, bool> Probe::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
std::vector<int> slots;
|
||||
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||
|
||||
return std::make_pair (slots, false);
|
||||
}
|
||||
|
||||
void Probe::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Probe);
|
||||
|
||||
registerClass (typeid (ESM::Probe).name(), instance);
|
||||
}
|
||||
|
||||
std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Probe Up");
|
||||
}
|
||||
|
||||
std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Probe Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class Probe : public MWWorld::Class
|
||||
|
@ -23,14 +22,20 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||
/// stay stacked when equipped?
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -19,7 +22,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -53,16 +56,12 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
||||
void Repair::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.repairs);
|
||||
}
|
||||
|
||||
std::string Repair::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Repair, MWWorld::RefData> *ref =
|
||||
|
@ -77,4 +76,14 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::Repair).name(), instance);
|
||||
}
|
||||
|
||||
std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Repair Up");
|
||||
}
|
||||
|
||||
std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
return std::string("Item Repair Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_REPAIR_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -23,14 +22,16 @@ namespace MWClass
|
|||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -15,11 +16,11 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), true);
|
||||
objects.insertMesh(ptr, "meshes\\" + model);
|
||||
}
|
||||
}
|
||||
|
@ -29,13 +30,12 @@ namespace MWClass
|
|||
ESMS::LiveCellRef<ESM::Static, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Static>();
|
||||
|
||||
|
||||
const std::string &model = ref->base->model;
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
if(!model.empty()){
|
||||
physics.insertObjectPhysics(ptr, "meshes\\" + model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string Static::getName (const MWWorld::Ptr& ptr) const
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_STATIC_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
#include "containerutil.hpp"
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -20,7 +23,7 @@ namespace MWClass
|
|||
|
||||
assert (ref->base != NULL);
|
||||
const std::string &model = ref->base->model;
|
||||
|
||||
|
||||
if (!model.empty())
|
||||
{
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
|
@ -54,6 +57,8 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
|
||||
{
|
||||
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true);
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action> (
|
||||
new MWWorld::ActionTake (ptr));
|
||||
}
|
||||
|
@ -71,12 +76,6 @@ namespace MWClass
|
|||
return ref->base->data.health;
|
||||
}
|
||||
|
||||
void Weapon::insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const
|
||||
{
|
||||
insertIntoContainerStore (ptr, containerStore.weapons);
|
||||
}
|
||||
|
||||
std::string Weapon::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||
|
@ -85,10 +84,157 @@ namespace MWClass
|
|||
return ref->base->script;
|
||||
}
|
||||
|
||||
std::pair<std::vector<int>, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Weapon>();
|
||||
|
||||
std::vector<int> slots;
|
||||
bool stack = false;
|
||||
|
||||
if (ref->base->data.type==ESM::Weapon::Arrow || ref->base->data.type==ESM::Weapon::Bolt)
|
||||
{
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_Ammunition));
|
||||
stack = true;
|
||||
}
|
||||
else if (ref->base->data.type==ESM::Weapon::MarksmanThrown)
|
||||
{
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||
stack = true;
|
||||
}
|
||||
else
|
||||
slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||
|
||||
return std::make_pair (slots, stack);
|
||||
}
|
||||
|
||||
int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Weapon>();
|
||||
|
||||
const int size = 12;
|
||||
|
||||
static const int sMapping[size][2] =
|
||||
{
|
||||
{ ESM::Weapon::ShortBladeOneHand, ESM::Skill::ShortBlade },
|
||||
{ ESM::Weapon::LongBladeOneHand, ESM::Skill::LongBlade },
|
||||
{ ESM::Weapon::LongBladeTwoHand, ESM::Skill::LongBlade },
|
||||
{ ESM::Weapon::BluntOneHand, ESM::Skill::BluntWeapon },
|
||||
{ ESM::Weapon::BluntTwoClose, ESM::Skill::BluntWeapon },
|
||||
{ ESM::Weapon::BluntTwoWide, ESM::Skill::BluntWeapon },
|
||||
{ ESM::Weapon::SpearTwoWide, ESM::Skill::Spear },
|
||||
{ ESM::Weapon::AxeOneHand, ESM::Skill::Axe },
|
||||
{ ESM::Weapon::AxeTwoHand, ESM::Skill::Axe },
|
||||
{ ESM::Weapon::MarksmanBow, ESM::Skill::Marksman },
|
||||
{ ESM::Weapon::MarksmanCrossbow, ESM::Skill::Marksman },
|
||||
{ ESM::Weapon::MarksmanThrown, ESM::Skill::Marksman }
|
||||
};
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
if (sMapping[i][0]==ref->base->data.type)
|
||||
return sMapping[i][1];
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Weapon::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Weapon);
|
||||
|
||||
registerClass (typeid (ESM::Weapon).name(), instance);
|
||||
}
|
||||
|
||||
std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Weapon>();
|
||||
|
||||
int type = ref->base->data.type;
|
||||
// Ammo
|
||||
if (type == 12 || type == 13)
|
||||
{
|
||||
return std::string("Item Ammo Up");
|
||||
}
|
||||
// Bow
|
||||
if (type == 9)
|
||||
{
|
||||
return std::string("Item Weapon Bow Up");
|
||||
}
|
||||
// Crossbow
|
||||
if (type == 10)
|
||||
{
|
||||
return std::string("Item Weapon Crossbow Up");
|
||||
}
|
||||
// Longblades, One hand and Two
|
||||
if (type == 1 || type == 2)
|
||||
{
|
||||
return std::string("Item Weapon Longblade Up");
|
||||
}
|
||||
// Shortblade and thrown weapons
|
||||
// thrown weapons may not be entirely correct
|
||||
if (type == 0 || type == 11)
|
||||
{
|
||||
return std::string("Item Weapon Shortblade Up");
|
||||
}
|
||||
// Spear
|
||||
if (type == 6)
|
||||
{
|
||||
return std::string("Item Weapon Spear Up");
|
||||
}
|
||||
// Blunts and Axes
|
||||
if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8)
|
||||
{
|
||||
return std::string("Item Weapon Blunt Up");
|
||||
}
|
||||
|
||||
return std::string("Item Misc Up");
|
||||
}
|
||||
|
||||
std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const
|
||||
{
|
||||
ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Weapon>();
|
||||
|
||||
int type = ref->base->data.type;
|
||||
// Ammo
|
||||
if (type == 12 || type == 13)
|
||||
{
|
||||
return std::string("Item Ammo Down");
|
||||
}
|
||||
// Bow
|
||||
if (type == 9)
|
||||
{
|
||||
return std::string("Item Weapon Bow Down");
|
||||
}
|
||||
// Crossbow
|
||||
if (type == 10)
|
||||
{
|
||||
return std::string("Item Weapon Crossbow Down");
|
||||
}
|
||||
// Longblades, One hand and Two
|
||||
if (type == 1 || type == 2)
|
||||
{
|
||||
return std::string("Item Weapon Longblade Down");
|
||||
}
|
||||
// Shortblade and thrown weapons
|
||||
// thrown weapons may not be entirely correct
|
||||
if (type == 0 || type == 11)
|
||||
{
|
||||
return std::string("Item Weapon Shortblade Down");
|
||||
}
|
||||
// Spear
|
||||
if (type == 6)
|
||||
{
|
||||
return std::string("Item Weapon Spear Down");
|
||||
}
|
||||
// Blunts and Axes
|
||||
if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8)
|
||||
{
|
||||
return std::string("Item Weapon Blunt Down");
|
||||
}
|
||||
|
||||
return std::string("Item Misc Down");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GAME_MWCLASS_WEAPON_H
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
@ -29,14 +28,25 @@ namespace MWClass
|
|||
virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const;
|
||||
///< Return item max health or throw an exception, if class does not have item health
|
||||
|
||||
virtual void insertIntoContainer (const MWWorld::Ptr& ptr,
|
||||
MWWorld::ContainerStore<MWWorld::RefData>& containerStore) const;
|
||||
///< Insert into a containe
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const;
|
||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||
/// stay stacked when equipped?
|
||||
|
||||
virtual int getEquipmentSkill (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Environment& environment) const;
|
||||
/// Return the index of the skill this item corresponds to when equiopped or -1, if there is
|
||||
/// no such skill.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the pick up sound Id
|
||||
|
||||
virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const;
|
||||
///< Return the put down sound Id
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace MWDialogue
|
|||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->data.disposition==index) /// \todo cleanup info structure
|
||||
{
|
||||
iter->id;
|
||||
return iter->id;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown journal index for topic " + topic);
|
||||
|
|
629
apps/openmw/mwgui/charactercreation.cpp
Normal file
629
apps/openmw/mwgui/charactercreation.cpp
Normal file
|
@ -0,0 +1,629 @@
|
|||
#include "charactercreation.hpp"
|
||||
|
||||
#include "text_input.hpp"
|
||||
#include "race.hpp"
|
||||
#include "class.hpp"
|
||||
#include "birth.hpp"
|
||||
#include "review.hpp"
|
||||
#include "dialogue.hpp"
|
||||
#include "mode.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Step
|
||||
{
|
||||
const char* mText;
|
||||
const char* mButtons[3];
|
||||
ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer
|
||||
};
|
||||
|
||||
static boost::array<Step, 10> sGenerateClassSteps = { {
|
||||
// Question 1
|
||||
{"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.",
|
||||
{"Draw your dagger, mercifully endings its life with a single thrust.",
|
||||
"Use herbs from your pack to put it to sleep.",
|
||||
"Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 2
|
||||
{"One Summer afternoon your father gives you a choice of chores.",
|
||||
{"Work in the forge with him casting iron for a new plow.",
|
||||
"Gather herbs for your mother who is preparing dinner.",
|
||||
"Go catch fish at the stream using a net and line."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 3
|
||||
{"Your cousin has given you a very embarrassing nickname and, even worse, likes to call you it in front of your friends. You asked him to stop, but he finds it very amusing to watch you blush.",
|
||||
{"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.",
|
||||
"Make up a story that makes your nickname a badge of honor instead of something humiliating.",
|
||||
"Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 4
|
||||
{"There is a lot of heated discussion at the local tavern over a grouped of people called 'Telepaths'. They have been hired by certain City-State kings. Rumor has it these Telepaths read a person's mind and tell their lord whether a follower is telling the truth or not.",
|
||||
{"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.",
|
||||
"Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.",
|
||||
"In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 5
|
||||
{"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.",
|
||||
{"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?",
|
||||
"Decide to put the extra money to good use and purchase items that would help your family?",
|
||||
"Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 6
|
||||
{"While in the market place you witness a thief cut a purse from a noble. Even as he does so, the noble notices and calls for the city guards. In his haste to get away, the thief drops the purse near you. Surprisingly no one seems to notice the bag of coins at your feet.",
|
||||
{"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.",
|
||||
"Leave the bag there, knowing that it is better not to get involved.",
|
||||
"Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 7
|
||||
{"Your father sends you on a task which you loathe, cleaning the stables. On the way there, pitchfork in hand, you run into your friend from the homestead near your own. He offers to do it for you, in return for a future favor of his choosing.",
|
||||
{"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.",
|
||||
"Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.",
|
||||
"Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 8
|
||||
{"Your mother asks you to help fix the stove. While you are working, a very hot pipe slips its mooring and falls towards her.",
|
||||
{"Position yourself between the pipe and your mother.",
|
||||
"Grab the hot pipe and try to push it away.",
|
||||
"Push your mother out of the way."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 9
|
||||
{"While in town the baker gives you a sweetroll. Delighted, you take it into an alley to enjoy only to be intercepted by a gang of three other kids your age. The leader demands the sweetroll, or else he and his friends will beat you and take it.",
|
||||
{"Drop the sweetroll and step on it, then get ready for the fight.",
|
||||
"Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.",
|
||||
"Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 10
|
||||
{"Entering town you find that you are witness to a very well-dressed man running from a crowd. He screams to you for help. The crowd behind him seem very angry.",
|
||||
{"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.",
|
||||
"Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.",
|
||||
"Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
}
|
||||
} };
|
||||
}
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
CharacterCreation::CharacterCreation(WindowManager* _wm, MWWorld::Environment* _environment)
|
||||
: mNameDialog(0)
|
||||
, mRaceDialog(0)
|
||||
, mDialogueWindow(0)
|
||||
, mClassChoiceDialog(0)
|
||||
, mGenerateClassQuestionDialog(0)
|
||||
, mGenerateClassResultDialog(0)
|
||||
, mPickClassDialog(0)
|
||||
, mCreateClassDialog(0)
|
||||
, mBirthSignDialog(0)
|
||||
, mReviewDialog(0)
|
||||
, mWM(_wm)
|
||||
, mEnvironment(_environment)
|
||||
{
|
||||
mCreationStage = CSE_NotStarted;
|
||||
}
|
||||
|
||||
void CharacterCreation::spawnDialog(const char id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case GM_Name:
|
||||
if(mNameDialog)
|
||||
mWM->removeDialog(mNameDialog);
|
||||
mNameDialog = new TextInputDialog(*mWM);
|
||||
mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name"));
|
||||
mNameDialog->setTextInput(mPlayerName);
|
||||
mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen);
|
||||
mNameDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone);
|
||||
mNameDialog->open();
|
||||
break;
|
||||
|
||||
case GM_Race:
|
||||
if (mRaceDialog)
|
||||
mWM->removeDialog(mRaceDialog);
|
||||
mRaceDialog = new RaceDialog(*mWM);
|
||||
mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen);
|
||||
mRaceDialog->setRaceId(mPlayerRaceId);
|
||||
mRaceDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
|
||||
mRaceDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
|
||||
mRaceDialog->open();
|
||||
break;
|
||||
|
||||
case GM_Class:
|
||||
if (mClassChoiceDialog)
|
||||
mWM->removeDialog(mClassChoiceDialog);
|
||||
mClassChoiceDialog = new ClassChoiceDialog(*mWM);
|
||||
mClassChoiceDialog->eventButtonSelected = MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
|
||||
mClassChoiceDialog->open();
|
||||
break;
|
||||
|
||||
case GM_ClassPick:
|
||||
if (mPickClassDialog)
|
||||
mWM->removeDialog(mPickClassDialog);
|
||||
mPickClassDialog = new PickClassDialog(*mWM);
|
||||
mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
|
||||
mPickClassDialog->setClassId(mPlayerClass.name);
|
||||
mPickClassDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
|
||||
mPickClassDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
|
||||
mPickClassDialog->open();
|
||||
break;
|
||||
|
||||
case GM_Birth:
|
||||
if (mBirthSignDialog)
|
||||
mWM->removeDialog(mBirthSignDialog);
|
||||
mBirthSignDialog = new BirthDialog(*mWM);
|
||||
mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen);
|
||||
mBirthSignDialog->setBirthId(mPlayerBirthSignId);
|
||||
mBirthSignDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
|
||||
mBirthSignDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
|
||||
mBirthSignDialog->open();
|
||||
break;
|
||||
|
||||
case GM_ClassCreate:
|
||||
if (mCreateClassDialog)
|
||||
mWM->removeDialog(mCreateClassDialog);
|
||||
mCreateClassDialog = new CreateClassDialog(*mWM);
|
||||
mCreateClassDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
|
||||
mCreateClassDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
|
||||
mCreateClassDialog->open();
|
||||
break;
|
||||
case GM_ClassGenerate:
|
||||
mGenerateClassStep = 0;
|
||||
mGenerateClass = "";
|
||||
mGenerateClassSpecializations[0] = 0;
|
||||
mGenerateClassSpecializations[1] = 0;
|
||||
mGenerateClassSpecializations[2] = 0;
|
||||
showClassQuestionDialog();
|
||||
break;
|
||||
case GM_Review:
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
mReviewDialog = new ReviewDialog(*mWM);
|
||||
mReviewDialog->setPlayerName(mPlayerName);
|
||||
mReviewDialog->setRace(mPlayerRaceId);
|
||||
mReviewDialog->setClass(mPlayerClass);
|
||||
mReviewDialog->setBirthSign(mPlayerBirthSignId);
|
||||
|
||||
mReviewDialog->setHealth(mPlayerHealth);
|
||||
mReviewDialog->setMagicka(mPlayerMagicka);
|
||||
mReviewDialog->setFatigue(mPlayerFatigue);
|
||||
|
||||
{
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> >::iterator end = mPlayerAttributes.end();
|
||||
for (std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> >::iterator it = mPlayerAttributes.begin(); it != end; ++it)
|
||||
{
|
||||
mReviewDialog->setAttribute(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> >::iterator end = mPlayerSkillValues.end();
|
||||
for (std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> >::iterator it = mPlayerSkillValues.begin(); it != end; ++it)
|
||||
{
|
||||
mReviewDialog->setSkillValue(it->first, it->second);
|
||||
}
|
||||
mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills);
|
||||
}
|
||||
|
||||
mReviewDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
|
||||
mReviewDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
|
||||
mReviewDialog->eventActivateDialog = MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
|
||||
mReviewDialog->open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat<int>& value)
|
||||
{
|
||||
mPlayerHealth = value;
|
||||
}
|
||||
|
||||
void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat<int>& value)
|
||||
{
|
||||
mPlayerMagicka = value;
|
||||
}
|
||||
|
||||
void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat<int>& value)
|
||||
{
|
||||
mPlayerFatigue = value;
|
||||
}
|
||||
|
||||
void CharacterCreation::onReviewDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
|
||||
void CharacterCreation::onReviewDialogBack()
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
}
|
||||
|
||||
void CharacterCreation::onReviewActivateDialog(int parDialog)
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
mCreationStage = CSE_ReviewNext;
|
||||
|
||||
switch(parDialog)
|
||||
{
|
||||
case ReviewDialog::NAME_DIALOG:
|
||||
mWM->setGuiMode(GM_Name);
|
||||
break;
|
||||
case ReviewDialog::RACE_DIALOG:
|
||||
mWM->setGuiMode(GM_Race);
|
||||
break;
|
||||
case ReviewDialog::CLASS_DIALOG:
|
||||
mWM->setGuiMode(GM_Class);
|
||||
break;
|
||||
case ReviewDialog::BIRTHSIGN_DIALOG:
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
};
|
||||
}
|
||||
|
||||
void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mPickClassDialog)
|
||||
{
|
||||
const std::string &classId = mPickClassDialog->getClassId();
|
||||
if (!classId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(classId);
|
||||
const ESM::Class *klass = mEnvironment->mWorld->getStore().classes.find(classId);
|
||||
if (klass)
|
||||
{
|
||||
mPlayerClass = *klass;
|
||||
mWM->setPlayerClass(mPlayerClass);
|
||||
}
|
||||
mWM->removeDialog(mPickClassDialog);
|
||||
}
|
||||
|
||||
//TODO This bit gets repeated a few times; wrap it in a function
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_ClassChosen)
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onPickClassDialogBack()
|
||||
{
|
||||
if (mPickClassDialog)
|
||||
{
|
||||
const std::string classId = mPickClassDialog->getClassId();
|
||||
if (!classId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(classId);
|
||||
mWM->removeDialog(mPickClassDialog);
|
||||
}
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onClassChoice(int _index)
|
||||
{
|
||||
if (mClassChoiceDialog)
|
||||
{
|
||||
mWM->removeDialog(mClassChoiceDialog);
|
||||
}
|
||||
|
||||
switch(_index)
|
||||
{
|
||||
case ClassChoiceDialog::Class_Generate:
|
||||
mWM->setGuiMode(GM_ClassGenerate);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Pick:
|
||||
mWM->setGuiMode(GM_ClassPick);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Create:
|
||||
mWM->setGuiMode(GM_ClassCreate);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Back:
|
||||
mWM->setGuiMode(GM_Race);
|
||||
break;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
void CharacterCreation::onNameDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mNameDialog)
|
||||
{
|
||||
mPlayerName = mNameDialog->getTextInput();
|
||||
mWM->setValue("name", mPlayerName);
|
||||
mEnvironment->mMechanicsManager->setPlayerName(mPlayerName);
|
||||
mWM->removeDialog(mNameDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_NameChosen)
|
||||
mWM->setGuiMode(GM_Race);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_NameChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onRaceDialogBack()
|
||||
{
|
||||
if (mRaceDialog)
|
||||
{
|
||||
mPlayerRaceId = mRaceDialog->getRaceId();
|
||||
if (!mPlayerRaceId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male);
|
||||
mWM->removeDialog(mRaceDialog);
|
||||
}
|
||||
|
||||
mWM->setGuiMode(GM_Name);
|
||||
}
|
||||
|
||||
void CharacterCreation::onRaceDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mRaceDialog)
|
||||
{
|
||||
mPlayerRaceId = mRaceDialog->getRaceId();
|
||||
mWM->setValue("race", mPlayerRaceId);
|
||||
if (!mPlayerRaceId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male);
|
||||
mWM->removeDialog(mRaceDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if(mCreationStage >= CSE_RaceChosen)
|
||||
mWM->setGuiMode(GM_Class);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_RaceChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mBirthSignDialog)
|
||||
{
|
||||
mPlayerBirthSignId = mBirthSignDialog->getBirthId();
|
||||
mWM->setBirthSign(mPlayerBirthSignId);
|
||||
if (!mPlayerBirthSignId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerBirthsign(mPlayerBirthSignId);
|
||||
mWM->removeDialog(mBirthSignDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage >= CSE_BirthSignChosen)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_BirthSignChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onBirthSignDialogBack()
|
||||
{
|
||||
if (mBirthSignDialog)
|
||||
{
|
||||
mEnvironment->mMechanicsManager->setPlayerBirthsign(mBirthSignDialog->getBirthId());
|
||||
mWM->removeDialog(mBirthSignDialog);
|
||||
}
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mCreateClassDialog)
|
||||
{
|
||||
ESM::Class klass;
|
||||
klass.name = mCreateClassDialog->getName();
|
||||
klass.description = mCreateClassDialog->getDescription();
|
||||
klass.data.specialization = mCreateClassDialog->getSpecializationId();
|
||||
klass.data.isPlayable = 0x1;
|
||||
|
||||
std::vector<int> attributes = mCreateClassDialog->getFavoriteAttributes();
|
||||
assert(attributes.size() == 2);
|
||||
klass.data.attribute[0] = attributes[0];
|
||||
klass.data.attribute[1] = attributes[1];
|
||||
|
||||
std::vector<ESM::Skill::SkillEnum> majorSkills = mCreateClassDialog->getMajorSkills();
|
||||
std::vector<ESM::Skill::SkillEnum> minorSkills = mCreateClassDialog->getMinorSkills();
|
||||
assert(majorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
|
||||
assert(minorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
|
||||
for (size_t i = 0; i < sizeof(klass.data.skills)/sizeof(klass.data.skills[0]); ++i)
|
||||
{
|
||||
klass.data.skills[i][1] = majorSkills[i];
|
||||
klass.data.skills[i][0] = minorSkills[i];
|
||||
}
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(klass);
|
||||
mPlayerClass = klass;
|
||||
mWM->setPlayerClass(klass);
|
||||
|
||||
mWM->removeDialog(mCreateClassDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_ClassChosen)
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onCreateClassDialogBack()
|
||||
{
|
||||
if (mCreateClassDialog)
|
||||
mWM->removeDialog(mCreateClassDialog);
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onClassQuestionChosen(int _index)
|
||||
{
|
||||
if (mGenerateClassQuestionDialog)
|
||||
mWM->removeDialog(mGenerateClassQuestionDialog);
|
||||
if (_index < 0 || _index >= 3)
|
||||
{
|
||||
mWM->setGuiMode(GM_Class);
|
||||
return;
|
||||
}
|
||||
|
||||
ESM::Class::Specialization specialization = sGenerateClassSteps[mGenerateClassStep].mSpecializations[_index];
|
||||
if (specialization == ESM::Class::Stealth)
|
||||
++mGenerateClassSpecializations[0];
|
||||
else if (specialization == ESM::Class::Combat)
|
||||
++mGenerateClassSpecializations[1];
|
||||
else if (specialization == ESM::Class::Magic)
|
||||
++mGenerateClassSpecializations[2];
|
||||
++mGenerateClassStep;
|
||||
showClassQuestionDialog();
|
||||
}
|
||||
|
||||
void CharacterCreation::showClassQuestionDialog()
|
||||
{
|
||||
if (mGenerateClassStep == sGenerateClassSteps.size())
|
||||
{
|
||||
static boost::array<ClassPoint, 23> classes = { {
|
||||
{"Acrobat", {6, 2, 2}},
|
||||
{"Agent", {6, 1, 3}},
|
||||
{"Archer", {3, 5, 2}},
|
||||
{"Archer", {5, 5, 0}},
|
||||
{"Assassin", {6, 3, 1}},
|
||||
{"Barbarian", {3, 6, 1}},
|
||||
{"Bard", {3, 3, 3}},
|
||||
{"Battlemage", {1, 3, 6}},
|
||||
{"Crusader", {1, 6, 3}},
|
||||
{"Healer", {3, 1, 6}},
|
||||
{"Knight", {2, 6, 2}},
|
||||
{"Monk", {5, 3, 2}},
|
||||
{"Nightblade", {4, 2, 4}},
|
||||
{"Pilgrim", {5, 2, 3}},
|
||||
{"Rogue", {3, 4, 3}},
|
||||
{"Rogue", {4, 4, 2}},
|
||||
{"Rogue", {5, 4, 1}},
|
||||
{"Scout", {2, 5, 3}},
|
||||
{"Sorcerer", {2, 2, 6}},
|
||||
{"Spellsword", {2, 4, 4}},
|
||||
{"Spellsword", {5, 1, 4}},
|
||||
{"Witchhunter", {2, 3, 5}},
|
||||
{"Witchhunter", {5, 0, 5}}
|
||||
} };
|
||||
|
||||
int match = -1;
|
||||
for (unsigned i = 0; i < classes.size(); ++i)
|
||||
{
|
||||
if (mGenerateClassSpecializations[0] == classes[i].points[0] &&
|
||||
mGenerateClassSpecializations[1] == classes[i].points[1] &&
|
||||
mGenerateClassSpecializations[2] == classes[i].points[2])
|
||||
{
|
||||
match = i;
|
||||
mGenerateClass = classes[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match == -1)
|
||||
{
|
||||
if (mGenerateClassSpecializations[0] >= 7)
|
||||
mGenerateClass = "Thief";
|
||||
else if (mGenerateClassSpecializations[1] >= 7)
|
||||
mGenerateClass = "Warrior";
|
||||
else if (mGenerateClassSpecializations[2] >= 7)
|
||||
mGenerateClass = "Mage";
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl;
|
||||
mGenerateClass = "Thief";
|
||||
}
|
||||
}
|
||||
|
||||
if (mGenerateClassResultDialog)
|
||||
mWM->removeDialog(mGenerateClassResultDialog);
|
||||
mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM);
|
||||
mGenerateClassResultDialog->setClassId(mGenerateClass);
|
||||
mGenerateClassResultDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack);
|
||||
mGenerateClassResultDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone);
|
||||
mGenerateClassResultDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGenerateClassStep > sGenerateClassSteps.size())
|
||||
{
|
||||
mWM->setGuiMode(GM_Class);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGenerateClassQuestionDialog)
|
||||
mWM->removeDialog(mGenerateClassQuestionDialog);
|
||||
mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM);
|
||||
|
||||
InfoBoxDialog::ButtonList buttons;
|
||||
mGenerateClassQuestionDialog->setText(sGenerateClassSteps[mGenerateClassStep].mText);
|
||||
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[0]);
|
||||
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[1]);
|
||||
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[2]);
|
||||
mGenerateClassQuestionDialog->setButtons(buttons);
|
||||
mGenerateClassQuestionDialog->eventButtonSelected = MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
|
||||
mGenerateClassQuestionDialog->open();
|
||||
}
|
||||
|
||||
void CharacterCreation::onGenerateClassBack()
|
||||
{
|
||||
if(mCreationStage < CSE_ClassChosen)
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
|
||||
if (mGenerateClassResultDialog)
|
||||
mWM->removeDialog(mGenerateClassResultDialog);
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(mGenerateClass);
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onGenerateClassDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mGenerateClassResultDialog)
|
||||
mWM->removeDialog(mGenerateClassResultDialog);
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(mGenerateClass);
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_ClassChosen)
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterCreation::~CharacterCreation()
|
||||
{
|
||||
delete mNameDialog;
|
||||
delete mRaceDialog;
|
||||
delete mDialogueWindow;
|
||||
delete mClassChoiceDialog;
|
||||
delete mGenerateClassQuestionDialog;
|
||||
delete mGenerateClassResultDialog;
|
||||
delete mPickClassDialog;
|
||||
delete mCreateClassDialog;
|
||||
delete mBirthSignDialog;
|
||||
delete mReviewDialog;
|
||||
}
|
120
apps/openmw/mwgui/charactercreation.hpp
Normal file
120
apps/openmw/mwgui/charactercreation.hpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#ifndef CHARACTER_CREATION_HPP
|
||||
#define CHARACTER_CREATION_HPP
|
||||
|
||||
#include "window_manager.hpp"
|
||||
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
#include <components/esm_store/store.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
class WindowBase;
|
||||
|
||||
class TextInputDialog;
|
||||
class InfoBoxDialog;
|
||||
class RaceDialog;
|
||||
class DialogueWindow;
|
||||
class ClassChoiceDialog;
|
||||
class GenerateClassResultDialog;
|
||||
class PickClassDialog;
|
||||
class CreateClassDialog;
|
||||
class BirthDialog;
|
||||
class ReviewDialog;
|
||||
class MessageBoxManager;
|
||||
|
||||
class CharacterCreation
|
||||
{
|
||||
public:
|
||||
typedef std::vector<int> SkillList;
|
||||
|
||||
CharacterCreation(WindowManager* _wm, MWWorld::Environment* _environment);
|
||||
~CharacterCreation();
|
||||
|
||||
//Show a dialog
|
||||
void spawnDialog(const char id);
|
||||
|
||||
void setPlayerHealth (const MWMechanics::DynamicStat<int>& value);
|
||||
|
||||
void setPlayerMagicka (const MWMechanics::DynamicStat<int>& value);
|
||||
|
||||
void setPlayerFatigue (const MWMechanics::DynamicStat<int>& value);
|
||||
|
||||
private:
|
||||
//Dialogs
|
||||
TextInputDialog* mNameDialog;
|
||||
RaceDialog* mRaceDialog;
|
||||
DialogueWindow* mDialogueWindow;
|
||||
ClassChoiceDialog* mClassChoiceDialog;
|
||||
InfoBoxDialog* mGenerateClassQuestionDialog;
|
||||
GenerateClassResultDialog* mGenerateClassResultDialog;
|
||||
PickClassDialog* mPickClassDialog;
|
||||
CreateClassDialog* mCreateClassDialog;
|
||||
BirthDialog* mBirthSignDialog;
|
||||
ReviewDialog* mReviewDialog;
|
||||
|
||||
WindowManager* mWM;
|
||||
MWWorld::Environment* mEnvironment;
|
||||
|
||||
//Player data
|
||||
std::string mPlayerName;
|
||||
std::string mPlayerRaceId;
|
||||
std::string mPlayerBirthSignId;
|
||||
ESM::Class mPlayerClass;
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> > mPlayerAttributes;
|
||||
SkillList mPlayerMajorSkills, mPlayerMinorSkills;
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> > mPlayerSkillValues;
|
||||
MWMechanics::DynamicStat<int> mPlayerHealth;
|
||||
MWMechanics::DynamicStat<int> mPlayerMagicka;
|
||||
MWMechanics::DynamicStat<int> mPlayerFatigue;
|
||||
|
||||
//Class generation vars
|
||||
unsigned mGenerateClassStep; // Keeps track of current step in Generate Class dialog
|
||||
unsigned mGenerateClassSpecializations[3]; // A counter for each specialization which is increased when an answer is chosen
|
||||
std::string mGenerateClass; // In order: Stealth, Combat, Magic
|
||||
|
||||
////Dialog events
|
||||
//Name dialog
|
||||
void onNameDialogDone(WindowBase* parWindow);
|
||||
|
||||
//Race dialog
|
||||
void onRaceDialogDone(WindowBase* parWindow);
|
||||
void onRaceDialogBack();
|
||||
|
||||
//Class dialogs
|
||||
void onClassChoice(int _index);
|
||||
void onPickClassDialogDone(WindowBase* parWindow);
|
||||
void onPickClassDialogBack();
|
||||
void onCreateClassDialogDone(WindowBase* parWindow);
|
||||
void onCreateClassDialogBack();
|
||||
void showClassQuestionDialog();
|
||||
void onClassQuestionChosen(int _index);
|
||||
void onGenerateClassBack();
|
||||
void onGenerateClassDone(WindowBase* parWindow);
|
||||
|
||||
//Birthsign dialog
|
||||
void onBirthSignDialogDone(WindowBase* parWindow);
|
||||
void onBirthSignDialogBack();
|
||||
|
||||
//Review dialog
|
||||
void onReviewDialogDone(WindowBase* parWindow);
|
||||
void onReviewDialogBack();
|
||||
void onReviewActivateDialog(int parDialog);
|
||||
|
||||
enum CSE //Creation Stage Enum
|
||||
{
|
||||
CSE_NotStarted,
|
||||
CSE_NameChosen,
|
||||
CSE_RaceChosen,
|
||||
CSE_ClassChosen,
|
||||
CSE_BirthSignChosen,
|
||||
CSE_ReviewNext
|
||||
};
|
||||
|
||||
CSE mCreationStage; // Which state the character creating is in, controls back/next/ok buttons
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -50,7 +50,7 @@ namespace MWGui
|
|||
|
||||
return isGood();
|
||||
}
|
||||
catch (const Compiler::SourceException& error)
|
||||
catch (const Compiler::SourceException&)
|
||||
{
|
||||
// error has already been reported via error handler
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ namespace MWGui
|
|||
if( ( matches.front().find(' ') != string::npos ) ) {
|
||||
if( !has_front_quote )
|
||||
output.append(string("\""));
|
||||
return output.append(matches.front() + string("\" "));
|
||||
return output.append(matches.front() + string("\" "));
|
||||
}
|
||||
else if( has_front_quote ) {
|
||||
return output.append(matches.front() + string("\" "));
|
||||
|
@ -361,7 +361,7 @@ namespace MWGui
|
|||
/* Append the longest match to the end of the output string*/
|
||||
output.append(matches.front().substr( 0, i));
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
201
apps/openmw/mwgui/journalwindow.cpp
Normal file
201
apps/openmw/mwgui/journalwindow.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
#include "journalwindow.hpp"
|
||||
#include "window_manager.hpp"
|
||||
#include "../mwdialogue/journal.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
#include "../mwsound/soundmanager.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct book
|
||||
{
|
||||
int endLine;
|
||||
std::list<std::string> pages;
|
||||
};
|
||||
}
|
||||
|
||||
book formatText(std::string text,book mBook,int maxLine, int lineSize)
|
||||
{
|
||||
//stringList.push_back("");
|
||||
|
||||
int cLineSize = 0;
|
||||
int cLine = mBook.endLine +1;
|
||||
std::string cString;
|
||||
|
||||
if(mBook.pages.empty())
|
||||
{
|
||||
cString = "";
|
||||
cLine = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cString = mBook.pages.back() + std::string("\n");
|
||||
mBook.pages.pop_back();
|
||||
}
|
||||
|
||||
//std::string::iterator wordBegin = text.begin();
|
||||
//std::string::iterator wordEnd;
|
||||
|
||||
std::string cText = text;
|
||||
|
||||
while(cText.length() != 0)
|
||||
{
|
||||
size_t firstSpace = cText.find_first_of(' ');
|
||||
if(firstSpace == std::string::npos)
|
||||
{
|
||||
cString = cString + cText;
|
||||
mBook.pages.push_back(cString);
|
||||
//TODO:finnish this
|
||||
break;
|
||||
}
|
||||
if(static_cast<int> (firstSpace) + cLineSize <= lineSize)
|
||||
{
|
||||
cLineSize = firstSpace + cLineSize;
|
||||
cString = cString + cText.substr(0,firstSpace +1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLineSize = firstSpace;
|
||||
if(cLine +1 <= maxLine)
|
||||
{
|
||||
cLine = cLine + 1;
|
||||
cString = cString + std::string("\n") + cText.substr(0,firstSpace +1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLine = 0;
|
||||
mBook.pages.push_back(cString);
|
||||
cString = cText.substr(0,firstSpace +1);
|
||||
}
|
||||
}
|
||||
//std::cout << cText << "\n";
|
||||
//std::cout << cText.length();
|
||||
cText = cText.substr(firstSpace +1,cText.length() - firstSpace -1);
|
||||
}
|
||||
mBook.endLine = cLine;
|
||||
return mBook;
|
||||
//std::string
|
||||
}
|
||||
|
||||
|
||||
MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_journal_layout.xml", parWindowManager)
|
||||
, lastPos(0)
|
||||
{
|
||||
//setCoord(0,0,498, 342);
|
||||
center();
|
||||
|
||||
getWidget(mLeftTextWidget, "LeftText");
|
||||
getWidget(mRightTextWidget, "RightText");
|
||||
getWidget(mPrevBtn, "PrevPageBTN");
|
||||
mPrevBtn->eventMouseButtonClick = MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage);
|
||||
getWidget(mNextBtn, "NextPageBTN");
|
||||
mNextBtn->eventMouseButtonClick = MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage);
|
||||
//MyGUI::ItemBox* list = new MyGUI::ItemBox();
|
||||
//list->addItem("qaq","aqzazaz");
|
||||
//mScrollerWidget->addChildItem(list);
|
||||
//mScrollerWidget->addItem("dserzt",MyGUI::UString("fedgdfg"));
|
||||
//mEditWidget->addText("ljblsxdvdsfvgedfvdfvdkjfghldfjgn sdv,nhsxl;vvn lklksbvlksb lbsdflkbdSLKJGBLskdhbvl<kbvlqksbgkqsjhdvb");
|
||||
//mEditWidget->show();
|
||||
//mEditWidget->setEditStatic(true);
|
||||
mLeftTextWidget->addText("left texxxt ");
|
||||
mLeftTextWidget->setEditReadOnly(true);
|
||||
mRightTextWidget->setEditReadOnly(true);
|
||||
mRightTextWidget->setEditStatic(true);
|
||||
mLeftTextWidget->setEditStatic(true);
|
||||
mRightTextWidget->addText("Right texxt ");
|
||||
|
||||
//std::list<std::string> list = formatText("OpenMW rgh dsfg sqef srg ZT uzql n ZLIEHRF LQSJH GLOIjf qjfmj hslkdgn jlkdjhg qlr isgli shli uhs fiuh qksf cg ksjnf lkqsnbf ksbf sbfkl zbf kuyzflkj sbgdfkj zlfh ozhjfmo hzmfh lizuf rty qzt ezy tkyEZT RYYJ DG fgh is an open-source implementation of the game engine found in the game Morrowind. This is a dumb test text msodjbg smojg smoig fiiinnn");
|
||||
//std::list<std::string> list = formatText();
|
||||
//displayLeftText(list.front());
|
||||
|
||||
MyGUI::WindowPtr t = static_cast<MyGUI::WindowPtr>(mMainWidget);
|
||||
t->eventWindowChangeCoord = MyGUI::newDelegate(this, &JournalWindow::onWindowResize);
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::open()
|
||||
{
|
||||
mPageNumber = 0;
|
||||
std::string journalOpenSound = "book open";
|
||||
mWindowManager.getEnvironment().mSoundManager->playSound (journalOpenSound, 1.0, 1.0);
|
||||
if(mWindowManager.getEnvironment().mJournal->begin()!=mWindowManager.getEnvironment().mJournal->end())
|
||||
{
|
||||
book journal;
|
||||
journal.endLine = 0;
|
||||
|
||||
for(std::deque<MWDialogue::StampedJournalEntry>::const_iterator it = mWindowManager.getEnvironment().mJournal->begin();it!=mWindowManager.getEnvironment().mJournal->end();it++)
|
||||
{
|
||||
std::string a = it->getText(mWindowManager.getEnvironment().mWorld->getStore());
|
||||
journal = formatText(a,journal,10,17);
|
||||
journal.endLine = journal.endLine +1;
|
||||
journal.pages.back() = journal.pages.back() + std::string("\n");
|
||||
}
|
||||
//std::string a = mWindowManager.getEnvironment().mJournal->begin()->getText(mWindowManager.getEnvironment().mWorld->getStore());
|
||||
//std::list<std::string> journal = formatText(a,10,20,1);
|
||||
bool left = true;
|
||||
for(std::list<std::string>::iterator it = journal.pages.begin(); it != journal.pages.end();it++)
|
||||
{
|
||||
if(left)
|
||||
{
|
||||
leftPages.push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
rightPages.push_back(*it);
|
||||
}
|
||||
left = !left;
|
||||
}
|
||||
if(!left) rightPages.push_back("");
|
||||
|
||||
mPageNumber = leftPages.size()-1;
|
||||
displayLeftText(leftPages[mPageNumber]);
|
||||
displayRightText(rightPages[mPageNumber]);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << mWindowManager.getEnvironment().mJournal->begin()->getText(mWindowManager.getEnvironment().mWorld->getStore());
|
||||
}
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::onWindowResize(MyGUI::Window* window)
|
||||
{
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::displayLeftText(std::string text)
|
||||
{
|
||||
mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength());
|
||||
mLeftTextWidget->addText(text);
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::displayRightText(std::string text)
|
||||
{
|
||||
mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength());
|
||||
mRightTextWidget->addText(text);
|
||||
}
|
||||
|
||||
|
||||
void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender)
|
||||
{
|
||||
if(mPageNumber < int(leftPages.size())-1)
|
||||
{
|
||||
std::string nextSound = "book page2";
|
||||
mWindowManager.getEnvironment().mSoundManager->playSound (nextSound, 1.0, 1.0);
|
||||
mPageNumber = mPageNumber + 1;
|
||||
displayLeftText(leftPages[mPageNumber]);
|
||||
displayRightText(rightPages[mPageNumber]);
|
||||
}
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender)
|
||||
{
|
||||
if(mPageNumber > 0)
|
||||
{
|
||||
std::string prevSound = "book page";
|
||||
mWindowManager.getEnvironment().mSoundManager->playSound (prevSound, 1.0, 1.0);
|
||||
mPageNumber = mPageNumber - 1;
|
||||
displayLeftText(leftPages[mPageNumber]);
|
||||
displayRightText(rightPages[mPageNumber]);
|
||||
}
|
||||
}
|
57
apps/openmw/mwgui/journalwindow.hpp
Normal file
57
apps/openmw/mwgui/journalwindow.hpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef MWGUI_JOURNAL_H
|
||||
#define MWGUI_JOURNAL_H
|
||||
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "window_base.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
|
||||
class JournalWindow : public WindowBase
|
||||
{
|
||||
public:
|
||||
JournalWindow(WindowManager& parWindowManager);
|
||||
void open();
|
||||
|
||||
private:
|
||||
enum ColorStyle
|
||||
{
|
||||
CS_Sub,
|
||||
CS_Normal,
|
||||
CS_Super
|
||||
};
|
||||
|
||||
void onWindowResize(MyGUI::Window* window);
|
||||
|
||||
void displayLeftText(std::string text);
|
||||
void displayRightText(std::string text);
|
||||
|
||||
|
||||
/**
|
||||
*Called when next/prev button is used.
|
||||
*/
|
||||
void notifyNextPage(MyGUI::WidgetPtr _sender);
|
||||
void notifyPrevPage(MyGUI::WidgetPtr _sender);
|
||||
|
||||
static const int lineHeight;
|
||||
|
||||
MyGUI::WidgetPtr skillAreaWidget, skillClientWidget;
|
||||
MyGUI::VScrollPtr skillScrollerWidget;
|
||||
int lastPos, clientHeight;
|
||||
MyGUI::EditPtr mLeftTextWidget;
|
||||
MyGUI::EditPtr mRightTextWidget;
|
||||
MyGUI::ButtonPtr mPrevBtn;
|
||||
MyGUI::ButtonPtr mNextBtn;
|
||||
std::vector<std::string> leftPages;
|
||||
std::vector<std::string> rightPages;
|
||||
int mPageNumber; //store the number of the current left page
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -13,7 +13,7 @@
|
|||
using namespace MWGui;
|
||||
|
||||
|
||||
HUD::HUD(int width, int height, bool fpsSwitch)
|
||||
HUD::HUD(int width, int height, int fpsLevel)
|
||||
: Layout("openmw_hud_layout.xml")
|
||||
{
|
||||
setCoord(0,0, width, height);
|
||||
|
@ -37,10 +37,19 @@ HUD::HUD(int width, int height, bool fpsSwitch)
|
|||
|
||||
getWidget(crosshair, "Crosshair");
|
||||
|
||||
getWidget(fpsbox, "FPSBox");
|
||||
getWidget(fpscounter, "FPSCounter");
|
||||
|
||||
fpsbox->setVisible(fpsSwitch);
|
||||
if ( fpsLevel == 2 ){
|
||||
getWidget(fpsbox, "FPSBoxAdv");
|
||||
fpsbox->setVisible(true);
|
||||
getWidget(fpscounter, "FPSCounterAdv");
|
||||
}else if ( fpsLevel == 1 ){
|
||||
getWidget(fpsbox, "FPSBox");
|
||||
fpsbox->setVisible(true);
|
||||
getWidget(fpscounter, "FPSCounter");
|
||||
}else{
|
||||
getWidget(fpscounter, "FPSCounter");
|
||||
}
|
||||
getWidget(trianglecounter, "TriangleCounter");
|
||||
getWidget(batchcounter, "BatchCounter");
|
||||
|
||||
compass->setImageTexture("textures\\compass.dds");
|
||||
crosshair->setImageTexture("textures\\target.dds");
|
||||
|
@ -59,6 +68,15 @@ void HUD::setFPS(float fps)
|
|||
fpscounter->setCaption(boost::lexical_cast<std::string>((int)fps));
|
||||
}
|
||||
|
||||
void HUD::setTriangleCount(size_t count)
|
||||
{
|
||||
trianglecounter->setCaption(boost::lexical_cast<std::string>(count));
|
||||
}
|
||||
|
||||
void HUD::setBatchCount(size_t count)
|
||||
{
|
||||
batchcounter->setCaption(boost::lexical_cast<std::string>(count));
|
||||
}
|
||||
|
||||
void HUD::setStats(int h, int hmax, int m, int mmax, int s, int smax)
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace MWGui
|
|||
class HUD : public OEngine::GUI::Layout
|
||||
{
|
||||
public:
|
||||
HUD(int width, int height, bool fpsSwitch);
|
||||
HUD(int width, int height, int fpsLevel);
|
||||
void setStats(int h, int hmax, int m, int mmax, int s, int smax);
|
||||
void setWeapIcon(const char *str);
|
||||
void setSpellIcon(const char *str);
|
||||
|
@ -41,6 +41,8 @@ namespace MWGui
|
|||
void setEffect(const char *img);
|
||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
|
||||
void setFPS(float fps);
|
||||
void setTriangleCount(size_t count);
|
||||
void setBatchCount(size_t count);
|
||||
|
||||
MyGUI::ProgressPtr health, magicka, stamina;
|
||||
MyGUI::StaticImagePtr weapImage, spellImage;
|
||||
|
@ -53,6 +55,8 @@ namespace MWGui
|
|||
|
||||
MyGUI::WidgetPtr fpsbox;
|
||||
MyGUI::StaticTextPtr fpscounter;
|
||||
MyGUI::StaticTextPtr trianglecounter;
|
||||
MyGUI::StaticTextPtr batchcounter;
|
||||
};
|
||||
|
||||
class MapWindow : public OEngine::GUI::Layout
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace MWGui
|
|||
GM_MainMenu, // Main menu mode
|
||||
|
||||
GM_Console, // Console mode
|
||||
GM_Journal, // Journal mode
|
||||
|
||||
// None of the following are implemented yet
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
#include "window_manager.hpp"
|
||||
#include "layouts.hpp"
|
||||
#include "text_input.hpp"
|
||||
#include "race.hpp"
|
||||
#include "class.hpp"
|
||||
#include "birth.hpp"
|
||||
#include "review.hpp"
|
||||
#include "dialogue.hpp"
|
||||
#include "dialogue_history.hpp"
|
||||
|
@ -14,6 +11,8 @@
|
|||
#include "../mwinput/inputmanager.hpp"
|
||||
|
||||
#include "console.hpp"
|
||||
#include "journalwindow.hpp"
|
||||
#include "charactercreation.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
|
@ -21,29 +20,21 @@
|
|||
|
||||
using namespace MWGui;
|
||||
|
||||
WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment,
|
||||
const Compiler::Extensions& extensions, bool fpsSwitch, bool newGame)
|
||||
WindowManager::WindowManager(MWWorld::Environment& environment,
|
||||
const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath)
|
||||
: environment(environment)
|
||||
, nameDialog(nullptr)
|
||||
, raceDialog(nullptr)
|
||||
, dialogueWindow(nullptr)
|
||||
, classChoiceDialog(nullptr)
|
||||
, generateClassQuestionDialog(nullptr)
|
||||
, generateClassResultDialog(nullptr)
|
||||
, pickClassDialog(nullptr)
|
||||
, createClassDialog(nullptr)
|
||||
, birthSignDialog(nullptr)
|
||||
, reviewDialog(nullptr)
|
||||
, gui(_gui)
|
||||
, mode(GM_Game)
|
||||
, nextMode(GM_Game)
|
||||
, needModeChange(false)
|
||||
, shown(GW_ALL)
|
||||
, allowed(newGame ? GW_None : GW_ALL)
|
||||
{
|
||||
showFPSCounter = fpsSwitch;
|
||||
showFPSLevel = fpsLevel;
|
||||
|
||||
creationStage = NotStarted;
|
||||
// Set up the GUI system
|
||||
mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath);
|
||||
gui = mGuiManager->getGui();
|
||||
|
||||
//Register own widgets with MyGUI
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<DialogeHistory>("Widget");
|
||||
|
@ -53,19 +44,19 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment
|
|||
int w = gui->getViewSize().width;
|
||||
int h = gui->getViewSize().height;
|
||||
|
||||
hud = new HUD(w,h, showFPSCounter);
|
||||
hud = new HUD(w,h, showFPSLevel);
|
||||
menu = new MainMenu(w,h);
|
||||
map = new MapWindow();
|
||||
stats = new StatsWindow(*this);
|
||||
#if 0
|
||||
inventory = new InventoryWindow ();
|
||||
#endif
|
||||
console = new Console(w,h, environment, extensions);
|
||||
mJournal = new JournalWindow(*this);
|
||||
mMessageBoxManager = new MessageBoxManager(this);
|
||||
|
||||
// The HUD is always on
|
||||
hud->setVisible(true);
|
||||
|
||||
mCharGen = new CharacterCreation(this, &environment);
|
||||
|
||||
// Setup player stats
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
{
|
||||
|
@ -89,26 +80,17 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment
|
|||
|
||||
WindowManager::~WindowManager()
|
||||
{
|
||||
delete mGuiManager;
|
||||
delete console;
|
||||
delete mMessageBoxManager;
|
||||
delete hud;
|
||||
delete map;
|
||||
delete menu;
|
||||
delete stats;
|
||||
#if 0
|
||||
delete inventory;
|
||||
#endif
|
||||
|
||||
delete nameDialog;
|
||||
delete raceDialog;
|
||||
delete mJournal;
|
||||
delete dialogueWindow;
|
||||
delete classChoiceDialog;
|
||||
delete generateClassQuestionDialog;
|
||||
delete generateClassResultDialog;
|
||||
delete pickClassDialog;
|
||||
delete createClassDialog;
|
||||
delete birthSignDialog;
|
||||
delete reviewDialog;
|
||||
|
||||
delete mCharGen;
|
||||
|
||||
cleanupGarbage();
|
||||
}
|
||||
|
@ -135,12 +117,19 @@ void WindowManager::update()
|
|||
environment.mInputManager->setGuiMode(nextMode);
|
||||
nextMode = GM_Game;
|
||||
}
|
||||
if (showFPSCounter)
|
||||
if (showFPSLevel > 0)
|
||||
{
|
||||
hud->setFPS(mFPS);
|
||||
hud->setTriangleCount(mTriangleCount);
|
||||
hud->setBatchCount(mBatchCount);
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Environment& WindowManager::getEnvironment()
|
||||
{
|
||||
return environment;
|
||||
}
|
||||
|
||||
void WindowManager::setNextMode(GuiMode newMode)
|
||||
{
|
||||
nextMode = newMode;
|
||||
|
@ -158,16 +147,14 @@ void WindowManager::updateVisible()
|
|||
map->setVisible(false);
|
||||
menu->setVisible(false);
|
||||
stats->setVisible(false);
|
||||
#if 0
|
||||
inventory->setVisible(false);
|
||||
#endif
|
||||
console->disable();
|
||||
mJournal->setVisible(false);
|
||||
|
||||
// Mouse is visible whenever we're not in game mode
|
||||
gui->setVisiblePointer(isGuiMode());
|
||||
|
||||
// If in game mode, don't show anything.
|
||||
if(mode == GM_Game)
|
||||
if(mode == GM_Game) //Use a switch/case structure
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -185,126 +172,10 @@ void WindowManager::updateVisible()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_Name)
|
||||
//There must be a more elegant solution
|
||||
if (mode == GM_Name || mode == GM_Race || mode == GM_Class || mode == GM_ClassPick || mode == GM_ClassCreate || mode == GM_Birth || mode == GM_ClassGenerate || mode == GM_Review)
|
||||
{
|
||||
if (nameDialog)
|
||||
removeDialog(nameDialog);
|
||||
nameDialog = new TextInputDialog(*this);
|
||||
std::string sName = getGameSettingString("sName", "Name");
|
||||
nameDialog->setTextLabel(sName);
|
||||
nameDialog->setTextInput(playerName);
|
||||
nameDialog->setNextButtonShow(creationStage >= NameChosen);
|
||||
nameDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onNameDialogDone);
|
||||
nameDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_Race)
|
||||
{
|
||||
if (raceDialog)
|
||||
removeDialog(raceDialog);
|
||||
raceDialog = new RaceDialog(*this);
|
||||
raceDialog->setNextButtonShow(creationStage >= RaceChosen);
|
||||
raceDialog->setRaceId(playerRaceId);
|
||||
raceDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onRaceDialogDone);
|
||||
raceDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onRaceDialogBack);
|
||||
raceDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_Class)
|
||||
{
|
||||
if (classChoiceDialog)
|
||||
removeDialog(classChoiceDialog);
|
||||
classChoiceDialog = new ClassChoiceDialog(*this);
|
||||
classChoiceDialog->eventButtonSelected = MyGUI::newDelegate(this, &WindowManager::onClassChoice);
|
||||
classChoiceDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_ClassGenerate)
|
||||
{
|
||||
generateClassStep = 0;
|
||||
generateClass = "";
|
||||
generateClassSpecializations[0] = 0;
|
||||
generateClassSpecializations[1] = 0;
|
||||
generateClassSpecializations[2] = 0;
|
||||
showClassQuestionDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_ClassPick)
|
||||
{
|
||||
if (pickClassDialog)
|
||||
removeDialog(pickClassDialog);
|
||||
pickClassDialog = new PickClassDialog(*this);
|
||||
pickClassDialog->setNextButtonShow(creationStage >= ClassChosen);
|
||||
pickClassDialog->setClassId(playerClass.name);
|
||||
pickClassDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onPickClassDialogDone);
|
||||
pickClassDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onPickClassDialogBack);
|
||||
pickClassDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_ClassCreate)
|
||||
{
|
||||
if (createClassDialog)
|
||||
removeDialog(createClassDialog);
|
||||
createClassDialog = new CreateClassDialog(*this);
|
||||
createClassDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onCreateClassDialogDone);
|
||||
createClassDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onCreateClassDialogBack);
|
||||
createClassDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_Birth)
|
||||
{
|
||||
if (birthSignDialog)
|
||||
removeDialog(birthSignDialog);
|
||||
birthSignDialog = new BirthDialog(*this);
|
||||
birthSignDialog->setNextButtonShow(creationStage >= BirthSignChosen);
|
||||
birthSignDialog->setBirthId(playerBirthSignId);
|
||||
birthSignDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onBirthSignDialogDone);
|
||||
birthSignDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onBirthSignDialogBack);
|
||||
birthSignDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GM_Review)
|
||||
{
|
||||
if (reviewDialog)
|
||||
removeDialog(reviewDialog);
|
||||
reviewDialog = new ReviewDialog(*this);
|
||||
reviewDialog->setPlayerName(playerName);
|
||||
reviewDialog->setRace(playerRaceId);
|
||||
reviewDialog->setClass(playerClass);
|
||||
reviewDialog->setBirthSign(playerBirthSignId);
|
||||
|
||||
reviewDialog->setHealth(playerHealth);
|
||||
reviewDialog->setMagicka(playerMagicka);
|
||||
reviewDialog->setFatigue(playerFatigue);
|
||||
|
||||
{
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> >::iterator end = playerAttributes.end();
|
||||
for (std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> >::iterator it = playerAttributes.begin(); it != end; ++it)
|
||||
{
|
||||
reviewDialog->setAttribute(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> >::iterator end = playerSkillValues.end();
|
||||
for (std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> >::iterator it = playerSkillValues.begin(); it != end; ++it)
|
||||
{
|
||||
reviewDialog->setSkillValue(it->first, it->second);
|
||||
}
|
||||
reviewDialog->configureSkills(playerMajorSkills, playerMinorSkills);
|
||||
}
|
||||
|
||||
reviewDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onReviewDialogDone);
|
||||
reviewDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onReviewDialogBack);
|
||||
reviewDialog->eventActivateDialog = MyGUI::newDelegate(this, &WindowManager::onReviewActivateDialog);
|
||||
reviewDialog->open();
|
||||
mCharGen->spawnDialog(mode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -319,9 +190,6 @@ void WindowManager::updateVisible()
|
|||
// Show the windows we want
|
||||
map -> setVisible( (eff & GW_Map) != 0 );
|
||||
stats -> setVisible( (eff & GW_Stats) != 0 );
|
||||
#if 0
|
||||
// inventory -> setVisible( eff & GW_Inventory );
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -344,6 +212,12 @@ void WindowManager::updateVisible()
|
|||
return;
|
||||
}
|
||||
|
||||
if(mode == GM_Journal)
|
||||
{
|
||||
mJournal->setVisible(true);
|
||||
mJournal->open();
|
||||
return;
|
||||
}
|
||||
|
||||
// Unsupported mode, switch back to game
|
||||
// Note: The call will eventually end up this method again but
|
||||
|
@ -392,13 +266,34 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicS
|
|||
stats->setValue (id, value);
|
||||
hud->setValue (id, value);
|
||||
if (id == "HBar")
|
||||
{
|
||||
playerHealth = value;
|
||||
mCharGen->setPlayerHealth (value);
|
||||
}
|
||||
else if (id == "MBar")
|
||||
{
|
||||
playerMagicka = value;
|
||||
mCharGen->setPlayerMagicka (value);
|
||||
}
|
||||
else if (id == "FBar")
|
||||
{
|
||||
playerFatigue = value;
|
||||
mCharGen->setPlayerFatigue (value);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
MWMechanics::DynamicStat<int> WindowManager::getValue(const std::string& id)
|
||||
{
|
||||
if(id == "HBar")
|
||||
return playerHealth;
|
||||
else if (id == "MBar")
|
||||
return playerMagicka;
|
||||
else if (id == "FBar")
|
||||
return playerFatigue;
|
||||
}
|
||||
#endif
|
||||
|
||||
void WindowManager::setValue (const std::string& id, const std::string& value)
|
||||
{
|
||||
stats->setValue (id, value);
|
||||
|
@ -487,49 +382,6 @@ const std::string &WindowManager::getGameSettingString(const std::string &id, co
|
|||
return default_;
|
||||
}
|
||||
|
||||
void WindowManager::onNameDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (nameDialog)
|
||||
{
|
||||
playerName = nameDialog->getTextInput();
|
||||
environment.mMechanicsManager->setPlayerName(playerName);
|
||||
removeDialog(nameDialog);
|
||||
}
|
||||
|
||||
// Go to next dialog if name was previously chosen
|
||||
if (creationStage == ReviewNext)
|
||||
setGuiMode(GM_Review);
|
||||
else if (creationStage >= NameChosen)
|
||||
setGuiMode(GM_Race);
|
||||
else
|
||||
{
|
||||
creationStage = NameChosen;
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::onRaceDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (raceDialog)
|
||||
{
|
||||
playerRaceId = raceDialog->getRaceId();
|
||||
if (!playerRaceId.empty())
|
||||
environment.mMechanicsManager->setPlayerRace(playerRaceId, raceDialog->getGender() == RaceDialog::GM_Male);
|
||||
removeDialog(raceDialog);
|
||||
}
|
||||
|
||||
// Go to next dialog if race was previously chosen
|
||||
if (creationStage == ReviewNext)
|
||||
setGuiMode(GM_Review);
|
||||
else if(creationStage >= RaceChosen)
|
||||
setGuiMode(GM_Class);
|
||||
else
|
||||
{
|
||||
creationStage = RaceChosen;
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::onDialogueWindowBye()
|
||||
{
|
||||
if (dialogueWindow)
|
||||
|
@ -540,434 +392,11 @@ void WindowManager::onDialogueWindowBye()
|
|||
setGuiMode(GM_Game);
|
||||
}
|
||||
|
||||
void WindowManager::onRaceDialogBack()
|
||||
{
|
||||
if (raceDialog)
|
||||
{
|
||||
playerRaceId = raceDialog->getRaceId();
|
||||
if (!playerRaceId.empty())
|
||||
environment.mMechanicsManager->setPlayerRace(playerRaceId, raceDialog->getGender() == RaceDialog::GM_Male);
|
||||
removeDialog(raceDialog);
|
||||
}
|
||||
|
||||
setGuiMode(GM_Name);
|
||||
}
|
||||
|
||||
void WindowManager::onClassChoice(int _index)
|
||||
{
|
||||
if (classChoiceDialog)
|
||||
{
|
||||
removeDialog(classChoiceDialog);
|
||||
}
|
||||
|
||||
switch(_index)
|
||||
{
|
||||
case ClassChoiceDialog::Class_Generate:
|
||||
setGuiMode(GM_ClassGenerate);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Pick:
|
||||
setGuiMode(GM_ClassPick);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Create:
|
||||
setGuiMode(GM_ClassCreate);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Back:
|
||||
setGuiMode(GM_Race);
|
||||
break;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
void WindowManager::onFrame (float frameDuration)
|
||||
{
|
||||
mMessageBoxManager->onFrame(frameDuration);
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
struct Step
|
||||
{
|
||||
const char* text;
|
||||
const char* buttons[3];
|
||||
// The specialization for each answer
|
||||
ESM::Class::Specialization specializations[3];
|
||||
};
|
||||
|
||||
static boost::array<Step, 10> generateClassSteps = { {
|
||||
// Question 1
|
||||
{"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.",
|
||||
{"Draw your dagger, mercifully endings its life with a single thrust.",
|
||||
"Use herbs from your pack to put it to sleep.",
|
||||
"Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 2
|
||||
{"One Summer afternoon your father gives you a choice of chores.",
|
||||
{"Work in the forge with him casting iron for a new plow.",
|
||||
"Gather herbs for your mother who is preparing dinner.",
|
||||
"Go catch fish at the stream using a net and line."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 3
|
||||
{"Your cousin has given you a very embarrassing nickname and, even worse, likes to call you it in front of your friends. You asked him to stop, but he finds it very amusing to watch you blush.",
|
||||
{"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.",
|
||||
"Make up a story that makes your nickname a badge of honor instead of something humiliating.",
|
||||
"Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 4
|
||||
{"There is a lot of heated discussion at the local tavern over a grouped of people called 'Telepaths'. They have been hired by certain City-State kings. Rumor has it these Telepaths read a person's mind and tell their lord whether a follower is telling the truth or not.",
|
||||
{"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.",
|
||||
"Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.",
|
||||
"In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 5
|
||||
{"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.",
|
||||
{"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?",
|
||||
"Decide to put the extra money to good use and purchase items that would help your family?",
|
||||
"Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 6
|
||||
{"While in the market place you witness a thief cut a purse from a noble. Even as he does so, the noble notices and calls for the city guards. In his haste to get away, the thief drops the purse near you. Surprisingly no one seems to notice the bag of coins at your feet.",
|
||||
{"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.",
|
||||
"Leave the bag there, knowing that it is better not to get involved.",
|
||||
"Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 7
|
||||
{"Your father sends you on a task which you loathe, cleaning the stables. On the way there, pitchfork in hand, you run into your friend from the homestead near your own. He offers to do it for you, in return for a future favor of his choosing.",
|
||||
{"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.",
|
||||
"Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.",
|
||||
"Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 8
|
||||
{"Your mother asks you to help fix the stove. While you are working, a very hot pipe slips its mooring and falls towards her.",
|
||||
{"Position yourself between the pipe and your mother.",
|
||||
"Grab the hot pipe and try to push it away.",
|
||||
"Push your mother out of the way."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 9
|
||||
{"While in town the baker gives you a sweetroll. Delighted, you take it into an alley to enjoy only to be intercepted by a gang of three other kids your age. The leader demands the sweetroll, or else he and his friends will beat you and take it.",
|
||||
{"Drop the sweetroll and step on it, then get ready for the fight.",
|
||||
"Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.",
|
||||
"Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 10
|
||||
{"Entering town you find that you are witness to a very well-dressed man running from a crowd. He screams to you for help. The crowd behind him seem very angry.",
|
||||
{"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.",
|
||||
"Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.",
|
||||
"Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
}
|
||||
} };
|
||||
}
|
||||
|
||||
void WindowManager::showClassQuestionDialog()
|
||||
{
|
||||
if (generateClassStep == generateClassSteps.size())
|
||||
{
|
||||
|
||||
static boost::array<ClassPoint, 23> classes = { {
|
||||
{"Acrobat", {6, 2, 2}},
|
||||
{"Agent", {6, 1, 3}},
|
||||
{"Archer", {3, 5, 2}},
|
||||
{"Archer", {5, 5, 0}},
|
||||
{"Assassin", {6, 3, 1}},
|
||||
{"Barbarian", {3, 6, 1}},
|
||||
{"Bard", {3, 3, 3}},
|
||||
{"Battlemage", {1, 3, 6}},
|
||||
{"Crusader", {1, 6, 3}},
|
||||
{"Healer", {3, 1, 6}},
|
||||
{"Knight", {2, 6, 2}},
|
||||
{"Monk", {5, 3, 2}},
|
||||
{"Nightblade", {4, 2, 4}},
|
||||
{"Pilgrim", {5, 2, 3}},
|
||||
{"Rogue", {3, 4, 3}},
|
||||
{"Rogue", {4, 4, 2}},
|
||||
{"Rogue", {5, 4, 1}},
|
||||
{"Scout", {2, 5, 3}},
|
||||
{"Sorcerer", {2, 2, 6}},
|
||||
{"Spellsword", {2, 4, 4}},
|
||||
{"Spellsword", {5, 1, 4}},
|
||||
{"Witchhunter", {2, 3, 5}},
|
||||
{"Witchhunter", {5, 0, 5}}
|
||||
} };
|
||||
|
||||
int match = -1;
|
||||
for (unsigned i = 0; i < classes.size(); ++i)
|
||||
{
|
||||
if (generateClassSpecializations[0] == classes[i].points[0] &&
|
||||
generateClassSpecializations[1] == classes[i].points[1] &&
|
||||
generateClassSpecializations[2] == classes[i].points[2])
|
||||
{
|
||||
match = i;
|
||||
generateClass = classes[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match == -1)
|
||||
{
|
||||
if (generateClassSpecializations[0] >= 7)
|
||||
generateClass = "Thief";
|
||||
else if (generateClassSpecializations[1] >= 7)
|
||||
generateClass = "Warrior";
|
||||
else if (generateClassSpecializations[2] >= 7)
|
||||
generateClass = "Mage";
|
||||
else
|
||||
{
|
||||
std::cerr
|
||||
<< "Failed to deduce class from chosen answers in generate class dialog"
|
||||
<< std::endl;
|
||||
generateClass = "Thief";
|
||||
}
|
||||
}
|
||||
|
||||
if (generateClassResultDialog)
|
||||
removeDialog(generateClassResultDialog);
|
||||
generateClassResultDialog = new GenerateClassResultDialog(*this);
|
||||
generateClassResultDialog->setClassId(generateClass);
|
||||
generateClassResultDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onGenerateClassBack);
|
||||
generateClassResultDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onGenerateClassDone);
|
||||
generateClassResultDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (generateClassStep > generateClassSteps.size())
|
||||
{
|
||||
setGuiMode(GM_Class);
|
||||
return;
|
||||
}
|
||||
|
||||
if (generateClassQuestionDialog)
|
||||
removeDialog(generateClassQuestionDialog);
|
||||
generateClassQuestionDialog = new InfoBoxDialog(*this);
|
||||
|
||||
InfoBoxDialog::ButtonList buttons;
|
||||
generateClassQuestionDialog->setText(generateClassSteps[generateClassStep].text);
|
||||
buttons.push_back(generateClassSteps[generateClassStep].buttons[0]);
|
||||
buttons.push_back(generateClassSteps[generateClassStep].buttons[1]);
|
||||
buttons.push_back(generateClassSteps[generateClassStep].buttons[2]);
|
||||
generateClassQuestionDialog->setButtons(buttons);
|
||||
generateClassQuestionDialog->eventButtonSelected = MyGUI::newDelegate(this, &WindowManager::onClassQuestionChosen);
|
||||
generateClassQuestionDialog->open();
|
||||
}
|
||||
|
||||
void WindowManager::onClassQuestionChosen(int _index)
|
||||
{
|
||||
if (generateClassQuestionDialog)
|
||||
removeDialog(generateClassQuestionDialog);
|
||||
if (_index < 0 || _index >= 3)
|
||||
{
|
||||
setGuiMode(GM_Class);
|
||||
return;
|
||||
}
|
||||
|
||||
ESM::Class::Specialization specialization = generateClassSteps[generateClassStep].specializations[_index];
|
||||
if (specialization == ESM::Class::Stealth)
|
||||
++generateClassSpecializations[0];
|
||||
else if (specialization == ESM::Class::Combat)
|
||||
++generateClassSpecializations[1];
|
||||
else if (specialization == ESM::Class::Magic)
|
||||
++generateClassSpecializations[2];
|
||||
++generateClassStep;
|
||||
showClassQuestionDialog();
|
||||
}
|
||||
|
||||
void WindowManager::onGenerateClassBack()
|
||||
{
|
||||
if(creationStage < ClassChosen)
|
||||
creationStage = ClassChosen;
|
||||
|
||||
if (generateClassResultDialog)
|
||||
removeDialog(generateClassResultDialog);
|
||||
environment.mMechanicsManager->setPlayerClass(generateClass);
|
||||
|
||||
setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void WindowManager::onGenerateClassDone(WindowBase* parWindow)
|
||||
{
|
||||
if (generateClassResultDialog)
|
||||
removeDialog(generateClassResultDialog);
|
||||
environment.mMechanicsManager->setPlayerClass(generateClass);
|
||||
|
||||
// Go to next dialog if class was previously chosen
|
||||
if (creationStage == ReviewNext)
|
||||
setGuiMode(GM_Review);
|
||||
else if (creationStage >= ClassChosen)
|
||||
setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
creationStage = ClassChosen;
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WindowManager::onPickClassDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (pickClassDialog)
|
||||
{
|
||||
const std::string &classId = pickClassDialog->getClassId();
|
||||
if (!classId.empty())
|
||||
environment.mMechanicsManager->setPlayerClass(classId);
|
||||
const ESM::Class *klass = environment.mWorld->getStore().classes.find(classId);
|
||||
if (klass)
|
||||
playerClass = *klass;
|
||||
removeDialog(pickClassDialog);
|
||||
}
|
||||
|
||||
// Go to next dialog if class was previously chosen
|
||||
if (creationStage == ReviewNext)
|
||||
setGuiMode(GM_Review);
|
||||
else if (creationStage >= ClassChosen)
|
||||
setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
creationStage = ClassChosen;
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::onPickClassDialogBack()
|
||||
{
|
||||
if (pickClassDialog)
|
||||
{
|
||||
const std::string classId = pickClassDialog->getClassId();
|
||||
if (!classId.empty())
|
||||
environment.mMechanicsManager->setPlayerClass(classId);
|
||||
removeDialog(pickClassDialog);
|
||||
}
|
||||
|
||||
setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void WindowManager::onCreateClassDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (createClassDialog)
|
||||
{
|
||||
ESM::Class klass;
|
||||
klass.name = createClassDialog->getName();
|
||||
klass.description = createClassDialog->getDescription();
|
||||
klass.data.specialization = createClassDialog->getSpecializationId();
|
||||
klass.data.isPlayable = 0x1;
|
||||
|
||||
std::vector<int> attributes = createClassDialog->getFavoriteAttributes();
|
||||
assert(attributes.size() == 2);
|
||||
klass.data.attribute[0] = attributes[0];
|
||||
klass.data.attribute[1] = attributes[1];
|
||||
|
||||
std::vector<ESM::Skill::SkillEnum> majorSkills = createClassDialog->getMajorSkills();
|
||||
std::vector<ESM::Skill::SkillEnum> minorSkills = createClassDialog->getMinorSkills();
|
||||
assert(majorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
|
||||
assert(minorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
|
||||
for (size_t i = 0; i < sizeof(klass.data.skills)/sizeof(klass.data.skills[0]); ++i)
|
||||
{
|
||||
klass.data.skills[i][1] = majorSkills[i];
|
||||
klass.data.skills[i][0] = minorSkills[i];
|
||||
}
|
||||
environment.mMechanicsManager->setPlayerClass(klass);
|
||||
playerClass = klass;
|
||||
|
||||
removeDialog(createClassDialog);
|
||||
}
|
||||
|
||||
// Go to next dialog if class was previously chosen
|
||||
if (creationStage == ReviewNext)
|
||||
setGuiMode(GM_Review);
|
||||
else if (creationStage >= ClassChosen)
|
||||
setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
creationStage = ClassChosen;
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::onCreateClassDialogBack()
|
||||
{
|
||||
if (createClassDialog)
|
||||
removeDialog(createClassDialog);
|
||||
|
||||
setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void WindowManager::onBirthSignDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (birthSignDialog)
|
||||
{
|
||||
playerBirthSignId = birthSignDialog->getBirthId();
|
||||
if (!playerBirthSignId.empty())
|
||||
environment.mMechanicsManager->setPlayerBirthsign(playerBirthSignId);
|
||||
removeDialog(birthSignDialog);
|
||||
}
|
||||
|
||||
// Go to next dialog if birth sign was previously chosen
|
||||
if (creationStage >= BirthSignChosen)
|
||||
setGuiMode(GM_Review);
|
||||
else
|
||||
{
|
||||
creationStage = BirthSignChosen;
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::onBirthSignDialogBack()
|
||||
{
|
||||
if (birthSignDialog)
|
||||
{
|
||||
environment.mMechanicsManager->setPlayerBirthsign(birthSignDialog->getBirthId());
|
||||
removeDialog(birthSignDialog);
|
||||
}
|
||||
|
||||
setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void WindowManager::onReviewDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (reviewDialog)
|
||||
removeDialog(reviewDialog);
|
||||
|
||||
setGuiMode(GM_Game);
|
||||
}
|
||||
|
||||
void WindowManager::onReviewDialogBack()
|
||||
{
|
||||
if (reviewDialog)
|
||||
removeDialog(reviewDialog);
|
||||
|
||||
setGuiMode(GM_Birth);
|
||||
}
|
||||
|
||||
void WindowManager::onReviewActivateDialog(int parDialog)
|
||||
{
|
||||
if (reviewDialog)
|
||||
removeDialog(reviewDialog);
|
||||
creationStage = ReviewNext;
|
||||
|
||||
switch(parDialog)
|
||||
{
|
||||
case ReviewDialog::NAME_DIALOG:
|
||||
setGuiMode(GM_Name);
|
||||
break;
|
||||
case ReviewDialog::RACE_DIALOG:
|
||||
setGuiMode(GM_Race);
|
||||
break;
|
||||
case ReviewDialog::CLASS_DIALOG:
|
||||
setGuiMode(GM_Class);
|
||||
break;
|
||||
case ReviewDialog::BIRTHSIGN_DIALOG:
|
||||
setGuiMode(GM_Birth);
|
||||
};
|
||||
}
|
||||
|
||||
const ESMS::ESMStore& WindowManager::getStore() const
|
||||
{
|
||||
return environment.mWorld->getStore();
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
|
||||
MyGUI should be initialized separately before creating instances of
|
||||
this class.
|
||||
*/
|
||||
**/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include <components/esm_store/store.hpp>
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include <openengine/gui/manager.hpp>
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
#include "mode.hpp"
|
||||
|
||||
|
@ -32,6 +34,12 @@ namespace Compiler
|
|||
namespace MWWorld
|
||||
{
|
||||
class Environment;
|
||||
class World;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class MechanicsManager;
|
||||
}
|
||||
|
||||
namespace OEngine
|
||||
|
@ -51,17 +59,12 @@ namespace MWGui
|
|||
class StatsWindow;
|
||||
class InventoryWindow;
|
||||
class Console;
|
||||
class JournalWindow;
|
||||
class CharacterCreation;
|
||||
|
||||
class TextInputDialog;
|
||||
class InfoBoxDialog;
|
||||
class RaceDialog;
|
||||
class DialogueWindow;
|
||||
class ClassChoiceDialog;
|
||||
class GenerateClassResultDialog;
|
||||
class PickClassDialog;
|
||||
class CreateClassDialog;
|
||||
class BirthDialog;
|
||||
class ReviewDialog;
|
||||
class MessageBoxManager;
|
||||
|
||||
struct ClassPoint
|
||||
|
@ -79,92 +82,11 @@ namespace MWGui
|
|||
typedef std::vector<Faction> FactionList;
|
||||
typedef std::vector<int> SkillList;
|
||||
|
||||
private:
|
||||
MWWorld::Environment& environment;
|
||||
HUD *hud;
|
||||
MapWindow *map;
|
||||
MainMenu *menu;
|
||||
StatsWindow *stats;
|
||||
MessageBoxManager *mMessageBoxManager;
|
||||
#if 0
|
||||
InventoryWindow *inventory;
|
||||
#endif
|
||||
Console *console;
|
||||
|
||||
// Character creation
|
||||
TextInputDialog *nameDialog;
|
||||
RaceDialog *raceDialog;
|
||||
DialogueWindow *dialogueWindow;
|
||||
ClassChoiceDialog *classChoiceDialog;
|
||||
InfoBoxDialog *generateClassQuestionDialog;
|
||||
GenerateClassResultDialog *generateClassResultDialog;
|
||||
PickClassDialog *pickClassDialog;
|
||||
CreateClassDialog *createClassDialog;
|
||||
BirthDialog *birthSignDialog;
|
||||
ReviewDialog *reviewDialog;
|
||||
|
||||
// Keeps track of current step in Generate Class dialogs
|
||||
unsigned generateClassStep;
|
||||
// A counter for each specialization which is increased when an answer is chosen, in order: Stealth, Combat, Magic
|
||||
unsigned generateClassSpecializations[3];
|
||||
std::string generateClass;
|
||||
|
||||
// Various stats about player as needed by window manager
|
||||
std::string playerName;
|
||||
ESM::Class playerClass;
|
||||
std::string playerRaceId, playerBirthSignId;
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> > playerAttributes;
|
||||
SkillList playerMajorSkills, playerMinorSkills;
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> > playerSkillValues;
|
||||
MWMechanics::DynamicStat<int> playerHealth, playerMagicka, playerFatigue;
|
||||
|
||||
// Gui
|
||||
MyGUI::Gui *gui;
|
||||
|
||||
// Current gui mode
|
||||
GuiMode mode;
|
||||
|
||||
/**
|
||||
* Next mode to activate in update().
|
||||
*/
|
||||
GuiMode nextMode;
|
||||
/**
|
||||
* Whether a mode change is needed in update().
|
||||
* Will use @a nextMode as the new mode.
|
||||
*/
|
||||
bool needModeChange;
|
||||
|
||||
std::vector<OEngine::GUI::Layout*> garbageDialogs;
|
||||
void cleanupGarbage();
|
||||
|
||||
// Currently shown windows in inventory mode
|
||||
GuiWindow shown;
|
||||
|
||||
/* Currently ALLOWED windows in inventory mode. This is used at
|
||||
the start of the game, when windows are enabled one by one
|
||||
through script commands. You can manipulate this through using
|
||||
allow() and disableAll().
|
||||
|
||||
The setting should also affect visibility of certain HUD
|
||||
elements, but this is not done yet.
|
||||
*/
|
||||
GuiWindow allowed;
|
||||
|
||||
// Update visibility of all windows based on mode, shown and
|
||||
// allowed settings.
|
||||
void updateVisible();
|
||||
WindowManager(MWWorld::Environment& environment, const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath);
|
||||
virtual ~WindowManager();
|
||||
|
||||
void setGuiMode(GuiMode newMode);
|
||||
|
||||
bool showFPSCounter;
|
||||
float mFPS;
|
||||
|
||||
public:
|
||||
/// The constructor needs the main Gui object
|
||||
WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment,
|
||||
const Compiler::Extensions& extensions, bool fpsSwitch, bool newGame);
|
||||
virtual ~WindowManager();
|
||||
|
||||
/**
|
||||
* Should be called each frame to update windows/gui elements.
|
||||
* This could mean updating sizes of gui elements or opening
|
||||
|
@ -172,6 +94,8 @@ namespace MWGui
|
|||
*/
|
||||
void update();
|
||||
|
||||
MWWorld::Environment& getEnvironment();
|
||||
|
||||
void setMode(GuiMode newMode)
|
||||
{
|
||||
if (newMode==GM_Inventory && allowed==GW_None)
|
||||
|
@ -184,8 +108,7 @@ namespace MWGui
|
|||
|
||||
GuiMode getMode() const { return mode; }
|
||||
|
||||
// Everything that is not game mode is considered "gui mode"
|
||||
bool isGuiMode() const { return getMode() != GM_Game; }
|
||||
bool isGuiMode() const { return getMode() != GM_Game; } // Everything that is not game mode is considered "gui mode"
|
||||
|
||||
// Disallow all inventory mode windows
|
||||
void disallowAll()
|
||||
|
@ -203,56 +126,38 @@ namespace MWGui
|
|||
|
||||
MyGUI::Gui* getGui() const { return gui; }
|
||||
|
||||
void wmSetFPS(float fps) { mFPS = fps; }
|
||||
void wmUpdateFps(float fps, size_t triangleCount, size_t batchCount)
|
||||
{
|
||||
mFPS = fps;
|
||||
mTriangleCount = triangleCount;
|
||||
mBatchCount = batchCount;
|
||||
}
|
||||
|
||||
// MWMechanics::DynamicStat<int> getValue(const std::string& id);
|
||||
|
||||
///< Set value for the given ID.
|
||||
void setValue (const std::string& id, const MWMechanics::Stat<int>& value);
|
||||
///< Set value for the given ID.
|
||||
|
||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value);
|
||||
///< Set value for the given ID.
|
||||
|
||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
|
||||
///< Set value for the given ID.
|
||||
|
||||
void setValue (const std::string& id, const std::string& value);
|
||||
///< set value for the given ID.
|
||||
|
||||
void setValue (const std::string& id, int value);
|
||||
///< set value for the given ID.
|
||||
|
||||
void setPlayerClass (const ESM::Class &class_);
|
||||
///< set current class of player
|
||||
void setPlayerClass (const ESM::Class &class_); ///< set current class of player
|
||||
void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group.
|
||||
void setFactions (const FactionList& factions); ///< set faction and rank to display on stat window, use an empty vector to disable
|
||||
void setBirthSign (const std::string &signId); ///< set birth sign to display on stat window, use an empty string to disable.
|
||||
void setReputation (int reputation); ///< set the current reputation value
|
||||
void setBounty (int bounty); ///< set the current bounty value
|
||||
void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty
|
||||
|
||||
void configureSkills (const SkillList& major, const SkillList& minor);
|
||||
///< configure skill groups, each set contains the skill ID for that group.
|
||||
|
||||
void setFactions (const FactionList& factions);
|
||||
///< set faction and rank to display on stat window, use an empty vector to disable
|
||||
|
||||
void setBirthSign (const std::string &signId);
|
||||
///< set birth sign to display on stat window, use an empty string to disable.
|
||||
|
||||
void setReputation (int reputation);
|
||||
///< set the current reputation value
|
||||
|
||||
void setBounty (int bounty);
|
||||
///< set the current bounty value
|
||||
|
||||
void updateSkillArea();
|
||||
///< update display of skills, factions, birth sign, reputation and bounty
|
||||
|
||||
template<typename T>
|
||||
void removeDialog(T*& dialog);
|
||||
///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
|
||||
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
|
||||
void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
|
||||
|
||||
void removeDialog(OEngine::GUI::Layout* dialog);
|
||||
///< Hides dialog and schedules dialog to be deleted.
|
||||
|
||||
void messageBox (const std::string& message, const std::vector<std::string>& buttons);
|
||||
|
||||
int readPressedButton ();
|
||||
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
||||
int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
||||
void onFrame (float frameDuration);
|
||||
|
||||
/**
|
||||
|
@ -267,54 +172,58 @@ namespace MWGui
|
|||
const ESMS::ESMStore& getStore() const;
|
||||
|
||||
private:
|
||||
OEngine::GUI::MyGUIManager *mGuiManager;
|
||||
MWWorld::Environment& environment;
|
||||
HUD *hud;
|
||||
MapWindow *map;
|
||||
MainMenu *menu;
|
||||
StatsWindow *stats;
|
||||
MessageBoxManager *mMessageBoxManager;
|
||||
Console *console;
|
||||
JournalWindow* mJournal;
|
||||
DialogueWindow *dialogueWindow;
|
||||
|
||||
CharacterCreation* mCharGen;
|
||||
|
||||
// Various stats about player as needed by window manager
|
||||
ESM::Class playerClass;
|
||||
std::string playerName;
|
||||
std::string playerRaceId;
|
||||
std::string playerBirthSignId;
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> > playerAttributes;
|
||||
SkillList playerMajorSkills, playerMinorSkills;
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> > playerSkillValues;
|
||||
MWMechanics::DynamicStat<int> playerHealth, playerMagicka, playerFatigue;
|
||||
|
||||
|
||||
MyGUI::Gui *gui; // Gui
|
||||
GuiMode mode; // Current gui mode
|
||||
GuiMode nextMode; // Next mode to activate in update()
|
||||
bool needModeChange; //Whether a mode change is needed in update() [will use nextMode]
|
||||
|
||||
std::vector<OEngine::GUI::Layout*> garbageDialogs;
|
||||
void cleanupGarbage();
|
||||
|
||||
GuiWindow shown; // Currently shown windows in inventory mode
|
||||
|
||||
/* Currently ALLOWED windows in inventory mode. This is used at
|
||||
the start of the game, when windows are enabled one by one
|
||||
through script commands. You can manipulate this through using
|
||||
allow() and disableAll().
|
||||
|
||||
The setting should also affect visibility of certain HUD
|
||||
elements, but this is not done yet.
|
||||
*/
|
||||
GuiWindow allowed;
|
||||
|
||||
void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings
|
||||
|
||||
int showFPSLevel;
|
||||
float mFPS;
|
||||
size_t mTriangleCount;
|
||||
size_t mBatchCount;
|
||||
|
||||
void onDialogueWindowBye();
|
||||
|
||||
// Character generation: Name dialog
|
||||
void onNameDialogDone(WindowBase* parWindow);
|
||||
|
||||
// Character generation: Race dialog
|
||||
void onRaceDialogDone(WindowBase* parWindow);
|
||||
void onRaceDialogBack();
|
||||
|
||||
// Character generation: Choose class process
|
||||
void onClassChoice(int _index);
|
||||
|
||||
// Character generation: Generate Class
|
||||
void showClassQuestionDialog();
|
||||
void onClassQuestionChosen(int _index);
|
||||
void onGenerateClassBack();
|
||||
void onGenerateClassDone(WindowBase* parWindow);
|
||||
|
||||
// Character generation: Pick Class dialog
|
||||
void onPickClassDialogDone(WindowBase* parWindow);
|
||||
void onPickClassDialogBack();
|
||||
|
||||
// Character generation: Create Class dialog
|
||||
void onCreateClassDialogDone(WindowBase* parWindow);
|
||||
void onCreateClassDialogBack();
|
||||
|
||||
// Character generation: Birth sign dialog
|
||||
void onBirthSignDialogDone(WindowBase* parWindow);
|
||||
void onBirthSignDialogBack();
|
||||
|
||||
// Character generation: Review dialog
|
||||
void onReviewDialogDone(WindowBase* parWindow);
|
||||
void onReviewDialogBack();
|
||||
void onReviewActivateDialog(int parDialog);
|
||||
|
||||
enum CreationStageEnum
|
||||
{
|
||||
NotStarted,
|
||||
NameChosen,
|
||||
RaceChosen,
|
||||
ClassChosen,
|
||||
BirthSignChosen,
|
||||
ReviewNext
|
||||
};
|
||||
|
||||
// Which state the character creating is in, controls back/next/ok buttons
|
||||
CreationStageEnum creationStage;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -83,27 +83,14 @@ namespace MWInput
|
|||
MWGui::WindowManager &windows;
|
||||
OMW::Engine& mEngine;
|
||||
|
||||
// Count screenshots.
|
||||
int shotCount;
|
||||
|
||||
|
||||
/* InputImpl Methods */
|
||||
|
||||
// Write screenshot to file.
|
||||
void screenshot()
|
||||
{
|
||||
|
||||
// Find the first unused filename with a do-while
|
||||
char buf[50];
|
||||
do
|
||||
{
|
||||
snprintf(buf, 50, "screenshot%03d.png", shotCount++);
|
||||
} while (boost::filesystem::exists(buf));
|
||||
|
||||
ogre.screenshot(buf);
|
||||
mEngine.screenshot();
|
||||
}
|
||||
|
||||
|
||||
/* toggleInventory() is called when the user presses the button to toggle the inventory screen. */
|
||||
void toggleInventory()
|
||||
{
|
||||
|
@ -134,6 +121,21 @@ namespace MWInput
|
|||
else setGuiMode(GM_Console);
|
||||
}
|
||||
|
||||
void toggleJournal()
|
||||
{
|
||||
using namespace MWGui;
|
||||
|
||||
GuiMode mode = windows.getMode();
|
||||
|
||||
// Toggle between game mode and journal mode
|
||||
if(mode == GM_Game)
|
||||
setGuiMode(GM_Journal);
|
||||
else if(mode == GM_Journal)
|
||||
setGuiMode(GM_Game);
|
||||
|
||||
// .. but don't touch any other mode.
|
||||
}
|
||||
|
||||
void activate()
|
||||
{
|
||||
mEngine.activate();
|
||||
|
@ -168,8 +170,7 @@ namespace MWInput
|
|||
poller(input),
|
||||
player(_player),
|
||||
windows(_windows),
|
||||
mEngine (engine),
|
||||
shotCount(0)
|
||||
mEngine (engine)
|
||||
{
|
||||
using namespace OEngine::Input;
|
||||
using namespace OEngine::Render;
|
||||
|
@ -188,6 +189,8 @@ namespace MWInput
|
|||
"Toggle inventory screen");
|
||||
disp->funcs.bind(A_Console, boost::bind(&InputImpl::toggleConsole, this),
|
||||
"Toggle console");
|
||||
disp->funcs.bind(A_Journal, boost::bind(&InputImpl::toggleJournal, this),
|
||||
"Toggle journal");
|
||||
disp->funcs.bind(A_Activate, boost::bind(&InputImpl::activate, this),
|
||||
"Activate");
|
||||
disp->funcs.bind(A_AutoMove, boost::bind(&InputImpl::toggleAutoMove, this),
|
||||
|
@ -236,6 +239,7 @@ namespace MWInput
|
|||
disp->bind(A_Screenshot, KC_SYSRQ);
|
||||
disp->bind(A_Inventory, KC_I);
|
||||
disp->bind(A_Console, KC_F1);
|
||||
disp->bind(A_Journal, KC_J);
|
||||
disp->bind(A_Activate, KC_SPACE);
|
||||
disp->bind(A_AutoMove, KC_Z);
|
||||
disp->bind(A_ToggleSneak, KC_X);
|
||||
|
|
|
@ -250,6 +250,7 @@ namespace MWMechanics
|
|||
while (iter!=mActors.end())
|
||||
if (iter->getCell()==cellStore)
|
||||
{
|
||||
//std::cout << "Erasing an actor";
|
||||
mActors.erase (iter++);
|
||||
}
|
||||
else
|
||||
|
|
126
apps/openmw/mwrender/actors.cpp
Normal file
126
apps/openmw/mwrender/actors.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include "actors.hpp"
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace MWRender;
|
||||
using namespace NifOgre;
|
||||
|
||||
void Actors::setMwRoot(Ogre::SceneNode* root){
|
||||
mMwRoot = root;
|
||||
}
|
||||
void Actors::insertNPC(const MWWorld::Ptr& ptr){
|
||||
|
||||
insertBegin(ptr, true, true);
|
||||
NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend);
|
||||
|
||||
mAllActors[ptr] = anim;
|
||||
}
|
||||
void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
|
||||
Ogre::SceneNode* cellnode;
|
||||
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
|
||||
{
|
||||
//Create the scenenode and put it in the map
|
||||
cellnode = mMwRoot->createChildSceneNode();
|
||||
mCellSceneNodes[ptr.getCell()] = cellnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellnode = mCellSceneNodes[ptr.getCell()];
|
||||
}
|
||||
|
||||
Ogre::SceneNode* insert = cellnode->createChildSceneNode();
|
||||
const float *f = ptr.getRefData().getPosition().pos;
|
||||
insert->setPosition(f[0], f[1], f[2]);
|
||||
insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale);
|
||||
|
||||
// Convert MW rotation to a quaternion:
|
||||
f = ptr.getCellRef().pos.rot;
|
||||
|
||||
// Rotate around X axis
|
||||
Quaternion xr(Radian(-f[0]), Vector3::UNIT_X);
|
||||
|
||||
// Rotate around Y axis
|
||||
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y);
|
||||
|
||||
// Rotate around Z axis
|
||||
Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z);
|
||||
|
||||
// Rotates first around z, then y, then x
|
||||
insert->setOrientation(xr*yr*zr);
|
||||
if (!enabled)
|
||||
insert->setVisible (false);
|
||||
ptr.getRefData().setBaseNode(insert);
|
||||
|
||||
|
||||
}
|
||||
void Actors::insertCreature (const MWWorld::Ptr& ptr){
|
||||
|
||||
insertBegin(ptr, true, true);
|
||||
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend);
|
||||
//mAllActors.insert(std::pair<MWWorld::Ptr, Animation*>(ptr,anim));
|
||||
mAllActors[ptr] = anim;
|
||||
//mAllActors.push_back(&anim);*/
|
||||
}
|
||||
|
||||
bool Actors::deleteObject (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
delete mAllActors[ptr];
|
||||
mAllActors.erase(ptr);
|
||||
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
|
||||
{
|
||||
|
||||
Ogre::SceneNode *parent = base->getParentSceneNode();
|
||||
|
||||
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
|
||||
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
||||
if (iter->second==parent)
|
||||
{
|
||||
base->removeAndDestroyAllChildren();
|
||||
mRend.getScene()->destroySceneNode (base);
|
||||
ptr.getRefData().setBaseNode (0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Actors::removeCell(MWWorld::Ptr::CellStore* store){
|
||||
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
|
||||
{
|
||||
Ogre::SceneNode* base = mCellSceneNodes[store];
|
||||
base->removeAndDestroyAllChildren();
|
||||
mCellSceneNodes.erase(store);
|
||||
mRend.getScene()->destroySceneNode(base);
|
||||
base = 0;
|
||||
}
|
||||
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); )
|
||||
{
|
||||
if(iter->first.getCell() == store){
|
||||
delete iter->second;
|
||||
mAllActors.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){
|
||||
if(mAllActors.find(ptr) != mAllActors.end())
|
||||
mAllActors[ptr]->startScript(groupName, mode, number);
|
||||
}
|
||||
void Actors::skipAnimation (const MWWorld::Ptr& ptr){
|
||||
if(mAllActors.find(ptr) != mAllActors.end())
|
||||
mAllActors[ptr]->stopScript();
|
||||
}
|
||||
void Actors::update (float duration){
|
||||
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
|
||||
{
|
||||
(iter->second)->runAnimation(duration);
|
||||
}
|
||||
}
|
59
apps/openmw/mwrender/actors.hpp
Normal file
59
apps/openmw/mwrender/actors.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef _GAME_RENDER_ACTORS_H
|
||||
#define _GAME_RENDER_ACTORS_H
|
||||
|
||||
#include "components/esm_store/cell_store.hpp"
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
|
||||
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "npcanimation.hpp"
|
||||
#include "creatureanimation.hpp"
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
namespace MWRender{
|
||||
class Actors{
|
||||
OEngine::Render::OgreRenderer &mRend;
|
||||
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||
Ogre::SceneNode* mMwRoot;
|
||||
MWWorld::Environment& mEnvironment;
|
||||
std::map<MWWorld::Ptr, Animation*> mAllActors;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
Actors(OEngine::Render::OgreRenderer& _rend, MWWorld::Environment& _env): mRend(_rend), mEnvironment(_env){}
|
||||
~Actors(){}
|
||||
void setMwRoot(Ogre::SceneNode* root);
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertCreature (const MWWorld::Ptr& ptr);
|
||||
void insertNPC(const MWWorld::Ptr& ptr);
|
||||
bool deleteObject (const MWWorld::Ptr& ptr);
|
||||
///< \return found?
|
||||
|
||||
void removeCell(MWWorld::Ptr::CellStore* store);
|
||||
|
||||
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
|
||||
int number = 1);
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the rendered scene should be ignored.
|
||||
///
|
||||
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param number How offen the animation should be run
|
||||
|
||||
void skipAnimation (const MWWorld::Ptr& ptr);
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the rendered scene should be ignored.
|
||||
|
||||
void update (float duration);
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
480
apps/openmw/mwrender/animation.cpp
Normal file
480
apps/openmw/mwrender/animation.cpp
Normal file
|
@ -0,0 +1,480 @@
|
|||
#include "animation.hpp"
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
std::map<std::string, int> Animation::mUniqueIDs;
|
||||
|
||||
Animation::~Animation(){
|
||||
}
|
||||
|
||||
std::string Animation::getUniqueID(std::string mesh){
|
||||
int counter;
|
||||
std::string copy = mesh;
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
|
||||
if(mUniqueIDs.find(copy) == mUniqueIDs.end()){
|
||||
counter = mUniqueIDs[copy] = 0;
|
||||
}
|
||||
else{
|
||||
mUniqueIDs[copy] = mUniqueIDs[copy] + 1;
|
||||
counter = mUniqueIDs[copy];
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
if(counter > 99 && counter < 1000)
|
||||
out << "0";
|
||||
else if(counter > 9)
|
||||
out << "00";
|
||||
else
|
||||
out << "000";
|
||||
out << counter;
|
||||
return out.str();
|
||||
}
|
||||
void Animation::startScript(std::string groupname, int mode, int loops){
|
||||
//If groupname is recognized set animate to true
|
||||
//Set the start time and stop time
|
||||
//How many times to loop
|
||||
if(groupname == "all"){
|
||||
animate = loops;
|
||||
time = startTime;
|
||||
}
|
||||
else if(textmappings){
|
||||
|
||||
std::string startName = groupname + ": loop start";
|
||||
std::string stopName = groupname + ": loop stop";
|
||||
|
||||
bool first = false;
|
||||
|
||||
if(loops > 1){
|
||||
startName = groupname + ": loop start";
|
||||
stopName = groupname + ": loop stop";
|
||||
|
||||
for(std::map<std::string, float>::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){
|
||||
|
||||
std::string current = iter->first.substr(0, startName.size());
|
||||
std::transform(current.begin(), current.end(), current.begin(), ::tolower);
|
||||
std::string current2 = iter->first.substr(0, stopName.size());
|
||||
std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower);
|
||||
|
||||
if(current == startName){
|
||||
startTime = iter->second;
|
||||
animate = loops;
|
||||
time = startTime;
|
||||
first = true;
|
||||
}
|
||||
if(current2 == stopName){
|
||||
stopTime = iter->second;
|
||||
if(first)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!first){
|
||||
startName = groupname + ": start";
|
||||
stopName = groupname + ": stop";
|
||||
|
||||
for(std::map<std::string, float>::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){
|
||||
|
||||
std::string current = iter->first.substr(0, startName.size());
|
||||
std::transform(current.begin(), current.end(), current.begin(), ::tolower);
|
||||
std::string current2 = iter->first.substr(0, stopName.size());
|
||||
std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower);
|
||||
|
||||
if(current == startName){
|
||||
startTime = iter->second;
|
||||
animate = loops;
|
||||
time = startTime;
|
||||
first = true;
|
||||
}
|
||||
if(current2 == stopName){
|
||||
stopTime = iter->second;
|
||||
if(first)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
void Animation::stopScript(){
|
||||
animate = 0;
|
||||
}
|
||||
|
||||
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
|
||||
shapeNumber = 0;
|
||||
|
||||
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
|
||||
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
|
||||
|
||||
{
|
||||
//std::map<unsigned short, PosAndRot> vecPosRot;
|
||||
|
||||
Nif::NiTriShapeCopy& copy = *allshapesiter;
|
||||
std::vector<Ogre::Vector3>* allvertices = ©.vertices;
|
||||
|
||||
|
||||
|
||||
//std::set<unsigned int> vertices;
|
||||
//std::set<unsigned int> normals;
|
||||
//std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfovector = copy.boneinfo;
|
||||
std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >* verticesToChange = ©.vertsToWeights;
|
||||
|
||||
//std::cout << "Name " << copy.sname << "\n";
|
||||
Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0);
|
||||
Ogre::Real* pReal = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
|
||||
|
||||
|
||||
std::vector<Ogre::Vector3> initialVertices = copy.morph.getInitialVertices();
|
||||
//Each shape has multiple indices
|
||||
if(initialVertices.size() )
|
||||
{
|
||||
|
||||
if(copy.vertices.size() == initialVertices.size())
|
||||
{
|
||||
//Create if it doesn't already exist
|
||||
if(shapeIndexI.size() == static_cast<std::size_t> (shapeNumber))
|
||||
{
|
||||
std::vector<int> vec;
|
||||
shapeIndexI.push_back(vec);
|
||||
}
|
||||
if(time >= copy.morph.getStartTime() && time <= copy.morph.getStopTime()){
|
||||
float x;
|
||||
for (unsigned int i = 0; i < copy.morph.getAdditionalVertices().size(); i++){
|
||||
int j = 0;
|
||||
if(shapeIndexI[shapeNumber].size() <= i)
|
||||
shapeIndexI[shapeNumber].push_back(0);
|
||||
|
||||
|
||||
if(timeIndex(time,copy.morph.getRelevantTimes()[i],(shapeIndexI[shapeNumber])[i], j, x)){
|
||||
int indexI = (shapeIndexI[shapeNumber])[i];
|
||||
std::vector<Ogre::Vector3> relevantData = (copy.morph.getRelevantData()[i]);
|
||||
float v1 = relevantData[indexI].x;
|
||||
float v2 = relevantData[j].x;
|
||||
float t = v1 + (v2 - v1) * x;
|
||||
if ( t < 0 ) t = 0;
|
||||
if ( t > 1 ) t = 1;
|
||||
if( t != 0 && initialVertices.size() == copy.morph.getAdditionalVertices()[i].size())
|
||||
{
|
||||
for (unsigned int v = 0; v < initialVertices.size(); v++){
|
||||
initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
allvertices = &initialVertices;
|
||||
}
|
||||
shapeNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(verticesToChange->size() > 0){
|
||||
|
||||
for(std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >::iterator iter = verticesToChange->begin();
|
||||
iter != verticesToChange->end(); iter++)
|
||||
{
|
||||
std::vector<Nif::NiSkinData::IndividualWeight> inds = iter->second;
|
||||
int verIndex = iter->first;
|
||||
Ogre::Vector3 currentVertex = (*allvertices)[verIndex];
|
||||
Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]);
|
||||
Ogre::Bone *bonePtr = 0;
|
||||
|
||||
|
||||
|
||||
Ogre::Vector3 vecPos;
|
||||
Ogre::Quaternion vecRot;
|
||||
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot>::iterator result = vecRotPos.find(boneinfocopy);
|
||||
|
||||
if(result == vecRotPos.end()){
|
||||
bonePtr = skel->getBone(boneinfocopy->bonename);
|
||||
|
||||
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
|
||||
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
|
||||
|
||||
|
||||
PosAndRot both;
|
||||
both.vecPos = vecPos;
|
||||
both.vecRot = vecRot;
|
||||
vecRotPos[boneinfocopy] = both;
|
||||
|
||||
}
|
||||
else{
|
||||
PosAndRot both = result->second;
|
||||
vecPos = both.vecPos;
|
||||
vecRot = both.vecRot;
|
||||
}
|
||||
|
||||
Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight;
|
||||
|
||||
|
||||
|
||||
for(std::size_t i = 1; i < inds.size(); i++){
|
||||
boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]);
|
||||
result = vecRotPos.find(boneinfocopy);
|
||||
|
||||
|
||||
if(result == vecRotPos.end()){
|
||||
bonePtr = skel->getBone(boneinfocopy->bonename);
|
||||
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
|
||||
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
|
||||
|
||||
PosAndRot both;
|
||||
both.vecPos = vecPos;
|
||||
both.vecRot = vecRot;
|
||||
vecRotPos[boneinfocopy] = both;
|
||||
|
||||
}
|
||||
else{
|
||||
PosAndRot both = result->second;
|
||||
vecPos = both.vecPos;
|
||||
vecRot = both.vecRot;
|
||||
}
|
||||
|
||||
|
||||
absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight;
|
||||
|
||||
|
||||
}
|
||||
Ogre::Real* addr = (pReal + 3 * verIndex);
|
||||
*addr = absVertPos.x;
|
||||
*(addr+1) = absVertPos.y;
|
||||
*(addr+2) = absVertPos.z;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(copy.bonename);
|
||||
Ogre::Quaternion shaperot = copy.trafo.rotation;
|
||||
Ogre::Vector3 shapetrans = copy.trafo.trans;
|
||||
float shapescale = copy.trafo.scale;
|
||||
std::vector<std::string> boneSequence = copy.boneSequence;
|
||||
|
||||
Ogre::Vector3 transmult;
|
||||
Ogre::Quaternion rotmult;
|
||||
float scale;
|
||||
if(boneSequence.size() > 0){
|
||||
std::vector<std::string>::iterator boneSequenceIter = boneSequence.begin();
|
||||
if(skel->hasBone(*boneSequenceIter)){
|
||||
Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter);
|
||||
|
||||
|
||||
|
||||
|
||||
transmult = bonePtr->getPosition();
|
||||
rotmult = bonePtr->getOrientation();
|
||||
scale = bonePtr->getScale().x;
|
||||
boneSequenceIter++;
|
||||
|
||||
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
|
||||
{
|
||||
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){
|
||||
Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(*boneSequenceIter);
|
||||
// Computes C = B + AxC*scale
|
||||
transmult = transmult + rotmult * bonePtr->getPosition();
|
||||
rotmult = rotmult * bonePtr->getOrientation();
|
||||
scale = scale * bonePtr->getScale().x;
|
||||
}
|
||||
//std::cout << "Bone:" << *boneSequenceIter << " ";
|
||||
}
|
||||
transmult = transmult + rotmult * shapetrans;
|
||||
rotmult = rotmult * shaperot;
|
||||
scale = shapescale * scale;
|
||||
|
||||
//std::cout << "Position: " << transmult << "Rotation: " << rotmult << "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transmult = shapetrans;
|
||||
rotmult = shaperot;
|
||||
scale = shapescale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Computes C = B + AxC*scale
|
||||
// final_vector = old_vector + old_rotation*new_vector*old_scale/
|
||||
|
||||
for(unsigned int i = 0; i < allvertices->size(); i++){
|
||||
Ogre::Vector3 current = transmult + rotmult * (*allvertices)[i];
|
||||
Ogre::Real* addr = pReal + i * 3;
|
||||
*addr = current.x;
|
||||
*(addr+1) = current.y;
|
||||
*(addr + 2) = current.z;
|
||||
|
||||
}/*
|
||||
for(int i = 0; i < allnormals.size(); i++){
|
||||
Ogre::Vector3 current =rotmult * allnormals[i];
|
||||
Ogre::Real* addr = pRealNormal + i * 3;
|
||||
*addr = current.x;
|
||||
*(addr+1) = current.y;
|
||||
*(addr + 2) = current.z;
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
vbuf->unlock();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
bool Animation::timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x ){
|
||||
int count;
|
||||
if ( (count = times.size()) > 0 )
|
||||
{
|
||||
if ( time <= times[0] )
|
||||
{
|
||||
i = j = 0;
|
||||
x = 0.0;
|
||||
return true;
|
||||
}
|
||||
if ( time >= times[count - 1] )
|
||||
{
|
||||
i = j = count - 1;
|
||||
x = 0.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( i < 0 || i >= count )
|
||||
i = 0;
|
||||
|
||||
float tI = times[i];
|
||||
if ( time > tI )
|
||||
{
|
||||
j = i + 1;
|
||||
float tJ;
|
||||
while ( time >= ( tJ = times[j]) )
|
||||
{
|
||||
i = j++;
|
||||
tI = tJ;
|
||||
}
|
||||
x = ( time - tI ) / ( tJ - tI );
|
||||
return true;
|
||||
}
|
||||
else if ( time < tI )
|
||||
{
|
||||
j = i - 1;
|
||||
float tJ;
|
||||
while ( time <= ( tJ = times[j] ) )
|
||||
{
|
||||
i = j--;
|
||||
tI = tJ;
|
||||
}
|
||||
x = ( time - tI ) / ( tJ - tI );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = i;
|
||||
x = 0.0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void Animation::handleAnimationTransforms(){
|
||||
|
||||
|
||||
Ogre::SkeletonInstance* skel = base->getSkeleton();
|
||||
|
||||
|
||||
Ogre::Bone* b = skel->getRootBone();
|
||||
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick
|
||||
|
||||
skel->_updateTransforms();
|
||||
//skel->_notifyManualBonesDirty();
|
||||
|
||||
base->getAllAnimationStates()->_notifyDirty();
|
||||
//base->_updateAnimation();
|
||||
//base->_notifyMoved();
|
||||
|
||||
for(unsigned int i = 0; i < entityparts.size(); i++){
|
||||
//Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
|
||||
|
||||
//Ogre::Bone* b = skel->getRootBone();
|
||||
//b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
|
||||
|
||||
//entityparts[i]->getAllAnimationStates()->_notifyDirty();
|
||||
}
|
||||
|
||||
|
||||
std::vector<Nif::NiKeyframeData>::iterator iter;
|
||||
int slot = 0;
|
||||
if(transformations){
|
||||
for(iter = transformations->begin(); iter != transformations->end(); iter++){
|
||||
if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime())
|
||||
{
|
||||
slot++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float x;
|
||||
float x2;
|
||||
|
||||
const std::vector<Ogre::Quaternion> & quats = iter->getQuat();
|
||||
|
||||
const std::vector<float> & ttime = iter->gettTime();
|
||||
|
||||
|
||||
const std::vector<float> & rtime = iter->getrTime();
|
||||
int rindexJ = rindexI[slot];
|
||||
|
||||
timeIndex(time, rtime, rindexI[slot], rindexJ, x2);
|
||||
int tindexJ = tindexI[slot];
|
||||
|
||||
|
||||
const std::vector<Ogre::Vector3> & translist1 = iter->getTranslist1();
|
||||
|
||||
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
|
||||
|
||||
Ogre::Vector3 t;
|
||||
Ogre::Quaternion r;
|
||||
|
||||
bool bTrans = translist1.size() > 0;
|
||||
|
||||
|
||||
bool bQuats = quats.size() > 0;
|
||||
|
||||
if(skel->hasBone(iter->getBonename())){
|
||||
Ogre::Bone* bone = skel->getBone(iter->getBonename());
|
||||
if(bTrans){
|
||||
Ogre::Vector3 v1 = translist1[tindexI[slot]];
|
||||
Ogre::Vector3 v2 = translist1[tindexJ];
|
||||
t = (v1 + (v2 - v1) * x);
|
||||
bone->setPosition(t);
|
||||
|
||||
}
|
||||
if(bQuats){
|
||||
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
|
||||
bone->setOrientation(r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
slot++;
|
||||
}
|
||||
skel->_updateTransforms();
|
||||
base->getAllAnimationStates()->_notifyDirty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
73
apps/openmw/mwrender/animation.hpp
Normal file
73
apps/openmw/mwrender/animation.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef _GAME_RENDER_ANIMATION_H
|
||||
#define _GAME_RENDER_ANIMATION_H
|
||||
#include <components/nif/data.hpp>
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include <components/nif/node.hpp>
|
||||
#include <map>
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
struct PosAndRot{
|
||||
Ogre::Quaternion vecRot;
|
||||
Ogre::Vector3 vecPos;
|
||||
};
|
||||
|
||||
class Animation{
|
||||
|
||||
protected:
|
||||
Ogre::SceneNode* insert;
|
||||
OEngine::Render::OgreRenderer &mRend;
|
||||
MWWorld::Environment& mEnvironment;
|
||||
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot> vecRotPos;
|
||||
static std::map<std::string, int> mUniqueIDs;
|
||||
|
||||
|
||||
|
||||
std::vector<std::vector<Nif::NiTriShapeCopy>* > shapeparts; //All the NiTriShape data that we need for animating an npc
|
||||
|
||||
float time;
|
||||
float startTime;
|
||||
float stopTime;
|
||||
int animate;
|
||||
//Represents a rotation index for each bone
|
||||
std::vector<int>rindexI;
|
||||
//Represents a translation index for each bone
|
||||
std::vector<int>tindexI;
|
||||
|
||||
//Only shapes with morphing data will use a shape number
|
||||
int shapeNumber;
|
||||
std::vector<std::vector<int> > shapeIndexI;
|
||||
|
||||
//Ogre::SkeletonInstance* skel;
|
||||
std::vector<Nif::NiTriShapeCopy>* shapes; //All the NiTriShapeData for a creature
|
||||
std::vector<Ogre::Entity*> entityparts;
|
||||
|
||||
|
||||
std::vector<Nif::NiKeyframeData>* transformations;
|
||||
std::map<std::string,float>* textmappings;
|
||||
Ogre::Entity* base;
|
||||
void handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel);
|
||||
void handleAnimationTransforms();
|
||||
bool timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x );
|
||||
std::string getUniqueID(std::string mesh);
|
||||
|
||||
public:
|
||||
Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend): mRend(_rend), mEnvironment(_env), animate(0){};
|
||||
virtual void runAnimation(float timepassed) = 0;
|
||||
void startScript(std::string groupname, int mode, int loops);
|
||||
void stopScript();
|
||||
|
||||
|
||||
virtual ~Animation();
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
63
apps/openmw/mwrender/creatureanimation.cpp
Normal file
63
apps/openmw/mwrender/creatureanimation.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "creatureanimation.hpp"
|
||||
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace NifOgre;
|
||||
namespace MWRender{
|
||||
|
||||
CreatureAnimation::~CreatureAnimation(){
|
||||
|
||||
}
|
||||
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend): Animation(_env,_rend){
|
||||
insert = ptr.getRefData().getBaseNode();
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
assert (ref->base != NULL);
|
||||
if(!ref->base->model.empty()){
|
||||
const std::string &mesh = "meshes\\" + ref->base->model;
|
||||
std::string meshNumbered = mesh + getUniqueID(mesh) + ">|";
|
||||
NifOgre::NIFLoader::load(meshNumbered);
|
||||
base = mRend.getScene()->createEntity(meshNumbered);
|
||||
std::string meshZero = mesh + "0000>|";
|
||||
|
||||
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){
|
||||
|
||||
for(std::size_t init = 0; init < transformations->size(); init++){
|
||||
rindexI.push_back(0);
|
||||
tindexI.push_back(0);
|
||||
}
|
||||
stopTime = transformations->begin()->getStopTime();
|
||||
startTime = transformations->begin()->getStartTime();
|
||||
shapes = (NIFLoader::getSingletonPtr())->getShapes(meshZero);
|
||||
}
|
||||
textmappings = NIFLoader::getSingletonPtr()->getTextIndices(meshZero);
|
||||
insert->attachObject(base);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAnimation::runAnimation(float timepassed){
|
||||
vecRotPos.clear();
|
||||
if(animate > 0){
|
||||
//Add the amount of time passed to time
|
||||
|
||||
//Handle the animation transforms dependent on time
|
||||
|
||||
//Handle the shapes dependent on animation transforms
|
||||
time += timepassed;
|
||||
if(time >= stopTime){
|
||||
animate--;
|
||||
//std::cout << "Stopping the animation\n";
|
||||
if(animate == 0)
|
||||
time = stopTime;
|
||||
else
|
||||
time = startTime + (time - stopTime);
|
||||
}
|
||||
|
||||
handleAnimationTransforms();
|
||||
handleShapes(shapes, base, base->getSkeleton());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
26
apps/openmw/mwrender/creatureanimation.hpp
Normal file
26
apps/openmw/mwrender/creatureanimation.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef _GAME_RENDER_CREATUREANIMATION_H
|
||||
#define _GAME_RENDER_CREATUREANIMATION_H
|
||||
|
||||
#include "animation.hpp"
|
||||
#include <components/nif/node.hpp>
|
||||
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class CreatureAnimation: public Animation{
|
||||
|
||||
public:
|
||||
virtual ~CreatureAnimation();
|
||||
CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||
virtual void runAnimation(float timepassed);
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -1,2 +0,0 @@
|
|||
#include "creatures.hpp"
|
||||
using namespace MWRender;
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef _GAME_RENDER_CREATURES_H
|
||||
#define _GAME_RENDER_CREATURES_H
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
namespace MWRender{
|
||||
class Creatures{
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
284
apps/openmw/mwrender/npcanimation.cpp
Normal file
284
apps/openmw/mwrender/npcanimation.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
#include "npcanimation.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace NifOgre;
|
||||
namespace MWRender{
|
||||
NpcAnimation::~NpcAnimation(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend): Animation(_env,_rend){
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::NPC>();
|
||||
|
||||
//Part selection on last character of the file string
|
||||
// " Tri Chest
|
||||
// * Tri Tail
|
||||
// : Tri Left Foot
|
||||
// < Tri Right Foot
|
||||
// > Tri Left Hand
|
||||
// ? Tri Right Hand
|
||||
// | Normal
|
||||
|
||||
//Mirroring Parts on second to last character
|
||||
//suffix == '*'
|
||||
// vector = Ogre::Vector3(-1,1,1);
|
||||
// suffix == '?'
|
||||
// vector = Ogre::Vector3(1,-1,1);
|
||||
// suffix == '<'
|
||||
// vector = Ogre::Vector3(1,1,-1);
|
||||
|
||||
|
||||
std::string hairID = ref->base->hair;
|
||||
std::string headID = ref->base->head;
|
||||
std::string npcName = ref->base->name;
|
||||
//ESMStore::Races r =
|
||||
const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race);
|
||||
|
||||
|
||||
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
|
||||
char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2);
|
||||
bool female = tolower(secondtolast) == 'f';
|
||||
std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower);
|
||||
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";
|
||||
|
||||
/*std::cout << "Race: " << ref->base->race ;
|
||||
if(female){
|
||||
std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n";
|
||||
}
|
||||
else{
|
||||
std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n";
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
std::string smodel = "meshes\\base_anim.nif";
|
||||
if(beast)
|
||||
smodel = "meshes\\base_animkna.nif";
|
||||
|
||||
insert = ptr.getRefData().getBaseNode();
|
||||
assert(insert);
|
||||
|
||||
NifOgre::NIFLoader::load(smodel);
|
||||
|
||||
base = mRend.getScene()->createEntity(smodel);
|
||||
base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones
|
||||
//stay in the same place when we skipanim, or open a gui window
|
||||
|
||||
|
||||
|
||||
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel))){
|
||||
|
||||
for(unsigned int init = 0; init < transformations->size(); init++){
|
||||
rindexI.push_back(0);
|
||||
tindexI.push_back(0);
|
||||
}
|
||||
|
||||
stopTime = transformations->begin()->getStopTime();
|
||||
startTime = transformations->begin()->getStartTime();
|
||||
}
|
||||
textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel);
|
||||
insert->attachObject(base);
|
||||
|
||||
if(female)
|
||||
insert->scale(race->data.height.female, race->data.height.female, race->data.height.female);
|
||||
else
|
||||
insert->scale(race->data.height.male, race->data.height.male, race->data.height.male);
|
||||
std::string headModel = "meshes\\" +
|
||||
mEnvironment.mWorld->getStore().bodyParts.find(headID)->model;
|
||||
|
||||
std::string hairModel = "meshes\\" +
|
||||
mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model;
|
||||
const ESM::BodyPart *chest = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest");
|
||||
const ESM::BodyPart *upperleg = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg");
|
||||
const ESM::BodyPart *groin = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin");
|
||||
const ESM::BodyPart *arml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); //We need two
|
||||
const ESM::BodyPart *neck = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck");
|
||||
const ESM::BodyPart *knee = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee");
|
||||
const ESM::BodyPart *ankle = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle");
|
||||
const ESM::BodyPart *foot = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot");
|
||||
const ESM::BodyPart *feet = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet");
|
||||
const ESM::BodyPart *tail = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail");
|
||||
const ESM::BodyPart *wristl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); //We need two
|
||||
const ESM::BodyPart *forearml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); //We need two
|
||||
const ESM::BodyPart *handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); //We need two
|
||||
const ESM::BodyPart *hair = mEnvironment.mWorld->getStore().bodyParts.search(hairID);
|
||||
const ESM::BodyPart *head = mEnvironment.mWorld->getStore().bodyParts.search(headID);
|
||||
if(bodyRaceID == "b_n_argonian_f_")
|
||||
forearml = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); //We need two
|
||||
if(!handl)
|
||||
handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands");
|
||||
//const ESM::BodyPart* claviclel = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "clavicle");
|
||||
//const ESM::BodyPart* clavicler = claviclel;
|
||||
const ESM::BodyPart* handr = handl;
|
||||
const ESM::BodyPart* forearmr = forearml;
|
||||
const ESM::BodyPart* wristr = wristl;
|
||||
const ESM::BodyPart* armr = arml;
|
||||
|
||||
|
||||
if(upperleg){
|
||||
insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg");
|
||||
insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg");
|
||||
|
||||
}
|
||||
if(foot){
|
||||
if(bodyRaceID.compare("b_n_khajiit_m_") == 0)
|
||||
{
|
||||
feet = foot;
|
||||
}
|
||||
else
|
||||
{
|
||||
insertBoundedPart("meshes\\" + foot->model, "Right Foot");
|
||||
insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot");
|
||||
}
|
||||
}
|
||||
if(groin){
|
||||
insertBoundedPart("meshes\\" + groin->model, "Groin");
|
||||
}
|
||||
if(knee)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e
|
||||
insertBoundedPart("meshes\\" + knee->model, "Right Knee"); //e
|
||||
|
||||
}
|
||||
if(ankle){
|
||||
|
||||
insertBoundedPart("meshes\\" + ankle->model + "*|", "Left Ankle"); //Ogre::Quaternion(Ogre::Radian(3.14 / 4), Ogre::Vector3(1, 0, 0)),blank); //1,0,0, blank);
|
||||
insertBoundedPart("meshes\\" + ankle->model, "Right Ankle");
|
||||
}
|
||||
if (armr){
|
||||
insertBoundedPart("meshes\\" + armr->model, "Right Upper Arm");
|
||||
}
|
||||
if(arml){
|
||||
insertBoundedPart("meshes\\" + arml->model + "*|", "Left Upper Arm");
|
||||
}
|
||||
|
||||
if (forearmr)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + forearmr->model, "Right Forearm");
|
||||
}
|
||||
if(forearml)
|
||||
insertBoundedPart("meshes\\" + forearml->model + "*|", "Left Forearm");
|
||||
|
||||
if (wristr)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + wristr->model, "Right Wrist");
|
||||
}
|
||||
|
||||
if(wristl)
|
||||
insertBoundedPart("meshes\\" + wristl->model + "*|", "Left Wrist");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*if(claviclel)
|
||||
insertBoundedPart("meshes\\" + claviclel->model + "*|", "Left Clavicle", base);
|
||||
if(clavicler)
|
||||
insertBoundedPart("meshes\\" + clavicler->model , "Right Clavicle", base);*/
|
||||
|
||||
if(neck)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + neck->model, "Neck");
|
||||
}
|
||||
if(head)
|
||||
insertBoundedPart("meshes\\" + head->model, "Head");
|
||||
if(hair)
|
||||
insertBoundedPart("meshes\\" + hair->model, "Head");
|
||||
|
||||
if (chest){
|
||||
insertFreePart("meshes\\" + chest->model, ">\"", insert);
|
||||
|
||||
|
||||
}
|
||||
if (handr){
|
||||
insertFreePart("meshes\\" + handr->model , ">?", insert);
|
||||
|
||||
}
|
||||
if (handl){
|
||||
insertFreePart("meshes\\" + handl->model, ">>", insert);
|
||||
|
||||
}
|
||||
if(tail){
|
||||
insertFreePart("meshes\\" + tail->model, ">*", insert);
|
||||
}
|
||||
if(feet){
|
||||
std::string num = getUniqueID(feet->model);
|
||||
insertFreePart("meshes\\" + feet->model,"><", insert);
|
||||
insertFreePart("meshes\\" + feet->model,">:", insert);
|
||||
}
|
||||
//originalpos = insert->_getWorldAABB().getCenter();
|
||||
//originalscenenode = insert->getPosition();
|
||||
}
|
||||
|
||||
Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){
|
||||
|
||||
NIFLoader::load(mesh);
|
||||
Entity* ent = mRend.getScene()->createEntity(mesh);
|
||||
|
||||
base->attachObjectToBone(bonename, ent);
|
||||
return ent;
|
||||
}
|
||||
void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert){
|
||||
std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix;
|
||||
NIFLoader::load(meshNumbered);
|
||||
|
||||
Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered);
|
||||
|
||||
|
||||
|
||||
|
||||
insert->attachObject(ent);
|
||||
entityparts.push_back(ent);
|
||||
shapes = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix));
|
||||
if(shapes){
|
||||
shapeparts.push_back(shapes);
|
||||
handleShapes(shapes, ent, base->getSkeleton());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NpcAnimation::runAnimation(float timepassed){
|
||||
|
||||
//1. Add the amount of time passed to time
|
||||
|
||||
//2. Handle the animation transforms dependent on time
|
||||
|
||||
//3. Handle the shapes dependent on animation transforms
|
||||
if(animate > 0){
|
||||
time += timepassed;
|
||||
|
||||
if(time > stopTime){
|
||||
animate--;
|
||||
|
||||
if(animate == 0)
|
||||
time = stopTime;
|
||||
else
|
||||
time = startTime + (time - stopTime);
|
||||
}
|
||||
|
||||
handleAnimationTransforms();
|
||||
|
||||
std::vector<std::vector<Nif::NiTriShapeCopy>*>::iterator shapepartsiter = shapeparts.begin();
|
||||
std::vector<Ogre::Entity*>::iterator entitypartsiter = entityparts.begin();
|
||||
while(shapepartsiter != shapeparts.end())
|
||||
{
|
||||
vecRotPos.clear();
|
||||
std::vector<Nif::NiTriShapeCopy>* shapes = *shapepartsiter;
|
||||
Ogre::Entity* theentity = *entitypartsiter;
|
||||
|
||||
|
||||
handleShapes(shapes, theentity, base->getSkeleton());
|
||||
shapepartsiter++;
|
||||
entitypartsiter++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
30
apps/openmw/mwrender/npcanimation.hpp
Normal file
30
apps/openmw/mwrender/npcanimation.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef _GAME_RENDER_NPCANIMATION_H
|
||||
#define _GAME_RENDER_NPCANIMATION_H
|
||||
#include "animation.hpp"
|
||||
#include <components/nif/data.hpp>
|
||||
#include <components/nif/node.hpp>
|
||||
#include <components/nif/property.hpp>
|
||||
#include <components/nif/controller.hpp>
|
||||
#include <components/nif/extra.hpp>
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class NpcAnimation: public Animation{
|
||||
|
||||
|
||||
|
||||
public:
|
||||
NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||
virtual ~NpcAnimation();
|
||||
Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename);
|
||||
void insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert);
|
||||
virtual void runAnimation(float timepassed);
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -1,2 +0,0 @@
|
|||
#include "npcs.hpp"
|
||||
using namespace MWRender;
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef _GAME_RENDER_NPCS_H
|
||||
#define _GAME_RENDER_NPCS_H
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
namespace MWRender{
|
||||
class Npcs{
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -1,11 +1,11 @@
|
|||
#include "objects.hpp"
|
||||
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace MWRender;
|
||||
|
||||
|
||||
bool Objects::lightConst = false;
|
||||
float Objects::lightConstValue = 0.0f;
|
||||
|
||||
|
@ -23,11 +23,25 @@ bool Objects::lightOutQuadInLin = false;
|
|||
|
||||
int Objects::uniqueID = 0;
|
||||
|
||||
void Objects::setMwRoot(Ogre::SceneNode* root){
|
||||
mwRoot = root;
|
||||
void Objects::clearSceneNode (Ogre::SceneNode *node)
|
||||
{
|
||||
/// \todo This should probably be moved into OpenEngine at some point.
|
||||
for (int i=node->numAttachedObjects()-1; i>=0; --i)
|
||||
{
|
||||
Ogre::MovableObject *object = node->getAttachedObject (i);
|
||||
node->detachObject (object);
|
||||
mRenderer.getScene()->destroyMovableObject (object);
|
||||
}
|
||||
}
|
||||
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
|
||||
Ogre::SceneNode* root = mwRoot;
|
||||
|
||||
void Objects::setMwRoot(Ogre::SceneNode* root)
|
||||
{
|
||||
mMwRoot = root;
|
||||
}
|
||||
|
||||
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
||||
{
|
||||
Ogre::SceneNode* root = mMwRoot;
|
||||
Ogre::SceneNode* cellnode;
|
||||
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
|
||||
{
|
||||
|
@ -49,90 +63,98 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
|
|||
f = ptr.getCellRef().pos.rot;
|
||||
|
||||
// Rotate around X axis
|
||||
Quaternion xr(Radian(-f[0]), Vector3::UNIT_X);
|
||||
Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X);
|
||||
|
||||
// Rotate around Y axis
|
||||
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y);
|
||||
Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y);
|
||||
|
||||
// Rotate around Z axis
|
||||
Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z);
|
||||
Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z);
|
||||
|
||||
// Rotates first around z, then y, then x
|
||||
// Rotates first around z, then y, then x
|
||||
insert->setOrientation(xr*yr*zr);
|
||||
|
||||
if (!enabled)
|
||||
insert->setVisible (false);
|
||||
ptr.getRefData().setBaseNode(insert);
|
||||
isStatic = static_;
|
||||
|
||||
|
||||
mIsStatic = static_;
|
||||
}
|
||||
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh){
|
||||
|
||||
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||
{
|
||||
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
|
||||
assert(insert);
|
||||
|
||||
NifOgre::NIFLoader::load(mesh);
|
||||
Entity *ent = mRend.getScene()->createEntity(mesh);
|
||||
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh);
|
||||
|
||||
if(!isStatic)
|
||||
if(!mIsStatic)
|
||||
{
|
||||
insert->attachObject(ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ogre::StaticGeometry* sg = 0;
|
||||
if(mSG.find(ptr.getCell()) == mSG.end())
|
||||
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||
{
|
||||
uniqueID = uniqueID +1;
|
||||
sg = mRend.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
//Create the scenenode and put it in the map
|
||||
mSG[ptr.getCell()] = sg;
|
||||
mStaticGeometry[ptr.getCell()] = sg;
|
||||
|
||||
// This specifies the size of a single batch region.
|
||||
// If it is set too high:
|
||||
// - there will be problems choosing the correct lights
|
||||
// - the culling will be more inefficient
|
||||
// If it is set too low:
|
||||
// - there will be too many batches.
|
||||
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
|
||||
}
|
||||
else
|
||||
{
|
||||
sg = mSG[ptr.getCell()];
|
||||
sg = mStaticGeometry[ptr.getCell()];
|
||||
}
|
||||
|
||||
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
||||
sg->setRegionDimensions(Ogre::Vector3(100000,10000,100000));
|
||||
|
||||
|
||||
mRend.getScene()->destroyEntity(ent);
|
||||
mRenderer.getScene()->destroyEntity(ent);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius){
|
||||
Ogre::SceneNode* insert = mRend.getScene()->getSceneNode(ptr.getRefData().getHandle());
|
||||
|
||||
void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius)
|
||||
{
|
||||
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle());
|
||||
assert(insert);
|
||||
Ogre::Light *light = mRend.getScene()->createLight();
|
||||
Ogre::Light *light = mRenderer.getScene()->createLight();
|
||||
light->setDiffuseColour (r, g, b);
|
||||
|
||||
float cval=0.0f, lval=0.0f, qval=0.0f;
|
||||
|
||||
if(lightConst)
|
||||
cval = lightConstValue;
|
||||
if(!lightOutQuadInLin)
|
||||
{
|
||||
if(lightLinear)
|
||||
radius *= lightLinearRadiusMult;
|
||||
if(lightQuadratic)
|
||||
radius *= lightQuadraticRadiusMult;
|
||||
|
||||
if(lightLinear)
|
||||
lval = lightLinearValue / pow(radius, lightLinearMethod);
|
||||
if(lightQuadratic)
|
||||
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME:
|
||||
// Do quadratic or linear, depending if we're in an exterior or interior
|
||||
// cell, respectively. Ignore lightLinear and lightQuadratic.
|
||||
}
|
||||
if(!lightOutQuadInLin)
|
||||
{
|
||||
if(lightLinear)
|
||||
radius *= lightLinearRadiusMult;
|
||||
if(lightQuadratic)
|
||||
radius *= lightQuadraticRadiusMult;
|
||||
|
||||
light->setAttenuation(10*radius, cval, lval, qval);
|
||||
if(lightLinear)
|
||||
lval = lightLinearValue / pow(radius, lightLinearMethod);
|
||||
if(lightQuadratic)
|
||||
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME:
|
||||
// Do quadratic or linear, depending if we're in an exterior or interior
|
||||
// cell, respectively. Ignore lightLinear and lightQuadratic.
|
||||
}
|
||||
|
||||
insert->attachObject(light);
|
||||
light->setAttenuation(10*radius, cval, lval, qval);
|
||||
|
||||
insert->attachObject(light);
|
||||
}
|
||||
|
||||
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
||||
|
@ -145,8 +167,9 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
|||
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
||||
if (iter->second==parent)
|
||||
{
|
||||
clearSceneNode (base);
|
||||
base->removeAndDestroyAllChildren();
|
||||
mRend.getScene()->destroySceneNode (base);
|
||||
mRenderer.getScene()->destroySceneNode (base);
|
||||
ptr.getRefData().setBaseNode (0);
|
||||
return true;
|
||||
}
|
||||
|
@ -157,29 +180,35 @@ bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
|||
return true;
|
||||
}
|
||||
|
||||
void Objects::removeCell(MWWorld::Ptr::CellStore* store){
|
||||
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
||||
{
|
||||
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
|
||||
{
|
||||
Ogre::SceneNode* base = mCellSceneNodes[store];
|
||||
|
||||
for (int i=0; i<base->numChildren(); ++i)
|
||||
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i)));
|
||||
|
||||
base->removeAndDestroyAllChildren();
|
||||
mCellSceneNodes.erase(store);
|
||||
mRend.getScene()->destroySceneNode(base);
|
||||
mRenderer.getScene()->destroySceneNode(base);
|
||||
base = 0;
|
||||
}
|
||||
|
||||
|
||||
if(mSG.find(store) != mSG.end())
|
||||
if(mStaticGeometry.find(store) != mStaticGeometry.end())
|
||||
{
|
||||
Ogre::StaticGeometry* sg = mSG[store];
|
||||
mSG.erase(store);
|
||||
mRend.getScene()->destroyStaticGeometry (sg);
|
||||
Ogre::StaticGeometry* sg = mStaticGeometry[store];
|
||||
mStaticGeometry.erase(store);
|
||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||
sg = 0;
|
||||
}
|
||||
}
|
||||
void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell){
|
||||
if(mSG.find(&cell) != mSG.end())
|
||||
|
||||
void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
|
||||
{
|
||||
if(mStaticGeometry.find(&cell) != mStaticGeometry.end())
|
||||
{
|
||||
Ogre::StaticGeometry* sg = mSG[&cell];
|
||||
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
|
||||
sg->build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
#ifndef _GAME_RENDER_OBJECTS_H
|
||||
#define _GAME_RENDER_OBJECTS_H
|
||||
|
||||
#include "components/esm_store/cell_store.hpp"
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
#include <components/esm_store/cell_store.hpp>
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class Objects{
|
||||
OEngine::Render::OgreRenderer &mRend;
|
||||
OEngine::Render::OgreRenderer &mRenderer;
|
||||
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mSG;
|
||||
Ogre::SceneNode* mwRoot;
|
||||
bool isStatic;
|
||||
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
||||
Ogre::SceneNode* mMwRoot;
|
||||
bool mIsStatic;
|
||||
static int uniqueID;
|
||||
static bool lightConst;
|
||||
static float lightConstValue;
|
||||
|
@ -30,8 +31,12 @@ class Objects{
|
|||
static float lightQuadraticRadiusMult;
|
||||
|
||||
static bool lightOutQuadInLin;
|
||||
|
||||
void clearSceneNode (Ogre::SceneNode *node);
|
||||
///< Remove all movable objects from \a node.
|
||||
|
||||
public:
|
||||
Objects(OEngine::Render::OgreRenderer& _rend): mRend(_rend){}
|
||||
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer){}
|
||||
~Objects(){}
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
#ifndef _GAME_RENDERING_INTERFACE_H
|
||||
#define _GAME_RENDERING_INTERFACE_H
|
||||
namespace MWRender{
|
||||
class Npcs;
|
||||
class Creatures;
|
||||
class Objects;
|
||||
class Actors;
|
||||
class Player;
|
||||
|
||||
class RenderingInterface{
|
||||
public:
|
||||
virtual MWRender::Npcs& getNPCs() = 0;
|
||||
virtual MWRender::Creatures& getCreatures() = 0;
|
||||
virtual MWRender::Objects& getObjects() = 0;
|
||||
virtual MWRender::Player& getPlayer() = 0;
|
||||
virtual MWRender::Actors& getActors() = 0;
|
||||
virtual ~RenderingInterface(){};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,13 +19,10 @@ using namespace Ogre;
|
|||
|
||||
namespace MWRender {
|
||||
|
||||
|
||||
|
||||
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine)
|
||||
:rend(_rend), objects(rend), mDebugging(engine)
|
||||
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment)
|
||||
:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mDebugging(engine)
|
||||
{
|
||||
rend.createScene("PlayerCam", 55, 5);
|
||||
mSkyManager = MWRender::SkyManager::create(rend.getWindow(), rend.getCamera(), resDir);
|
||||
mRendering.createScene("PlayerCam", 55, 5);
|
||||
|
||||
// Set default mipmap level (NB some APIs ignore this)
|
||||
TextureManager::getSingleton().setDefaultNumMipmaps(5);
|
||||
|
@ -38,48 +35,64 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||
// the screen (when x is to the right.) This is the orientation that
|
||||
// Morrowind uses, and it automagically makes everything work as it
|
||||
// should.
|
||||
SceneNode *rt = rend.getScene()->getRootSceneNode();
|
||||
mwRoot = rt->createChildSceneNode();
|
||||
mwRoot->pitch(Degree(-90));
|
||||
objects.setMwRoot(mwRoot);
|
||||
|
||||
SceneNode *rt = mRendering.getScene()->getRootSceneNode();
|
||||
mMwRoot = rt->createChildSceneNode();
|
||||
mMwRoot->pitch(Degree(-90));
|
||||
mObjects.setMwRoot(mMwRoot);
|
||||
mActors.setMwRoot(mMwRoot);
|
||||
|
||||
//used to obtain ingame information of ogre objects (which are faced or selected)
|
||||
mRaySceneQuery = rend.getScene()->createRayQuery(Ray());
|
||||
mRaySceneQuery = mRendering.getScene()->createRayQuery(Ray());
|
||||
|
||||
Ogre::SceneNode *playerNode = mwRoot->createChildSceneNode ("player");
|
||||
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
|
||||
playerNode->pitch(Degree(90));
|
||||
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
|
||||
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
|
||||
cameraPitchNode->attachObject(rend.getCamera());
|
||||
cameraPitchNode->attachObject(mRendering.getCamera());
|
||||
|
||||
//mSkyManager = 0;
|
||||
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
|
||||
|
||||
mPlayer = new MWRender::Player (rend.getCamera(), playerNode);
|
||||
|
||||
mWater = 0;
|
||||
|
||||
//std::cout << "Three";
|
||||
|
||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||
mSun = 0;
|
||||
}
|
||||
|
||||
RenderingManager::~RenderingManager ()
|
||||
{
|
||||
//TODO: destroy mSun?
|
||||
delete mPlayer;
|
||||
delete mSkyManager;
|
||||
}
|
||||
|
||||
MWRender::Npcs& RenderingManager::getNPCs(){
|
||||
return npcs;
|
||||
MWRender::SkyManager* RenderingManager::getSkyManager()
|
||||
{
|
||||
return mSkyManager;
|
||||
}
|
||||
|
||||
MWRender::Objects& RenderingManager::getObjects(){
|
||||
return objects;
|
||||
return mObjects;
|
||||
}
|
||||
MWRender::Creatures& RenderingManager::getCreatures(){
|
||||
return creatures;
|
||||
MWRender::Actors& RenderingManager::getActors(){
|
||||
return mActors;
|
||||
}
|
||||
|
||||
MWRender::Player& RenderingManager::getPlayer(){
|
||||
return (*mPlayer);
|
||||
}
|
||||
|
||||
OEngine::Render::Fader* RenderingManager::getFader()
|
||||
{
|
||||
return mRendering.getFader();
|
||||
}
|
||||
|
||||
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store){
|
||||
objects.removeCell(store);
|
||||
|
||||
mObjects.removeCell(store);
|
||||
mActors.removeCell(store);
|
||||
|
||||
}
|
||||
void RenderingManager::removeWater (){
|
||||
|
@ -91,7 +104,7 @@ void RenderingManager::removeWater (){
|
|||
|
||||
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
||||
{
|
||||
objects.buildStaticGeometry (*store);
|
||||
mObjects.buildStaticGeometry (*store);
|
||||
}
|
||||
|
||||
void RenderingManager::addObject (const MWWorld::Ptr& ptr){
|
||||
|
@ -102,7 +115,11 @@ void RenderingManager::addObject (const MWWorld::Ptr& ptr){
|
|||
}
|
||||
void RenderingManager::removeObject (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (!objects.deleteObject (ptr))
|
||||
if (!mObjects.deleteObject (ptr))
|
||||
{
|
||||
/// \todo delete non-object MW-references
|
||||
}
|
||||
if (!mActors.deleteObject (ptr))
|
||||
{
|
||||
/// \todo delete non-object MW-references
|
||||
}
|
||||
|
@ -111,7 +128,7 @@ void RenderingManager::removeObject (const MWWorld::Ptr& ptr)
|
|||
void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position)
|
||||
{
|
||||
/// \todo move this to the rendering-subsystems
|
||||
rend.getScene()->getSceneNode (ptr.getRefData().getHandle())->
|
||||
mRendering.getScene()->getSceneNode (ptr.getRefData().getHandle())->
|
||||
setPosition (position);
|
||||
}
|
||||
|
||||
|
@ -127,12 +144,16 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
|
|||
|
||||
void RenderingManager::update (float duration){
|
||||
|
||||
|
||||
mActors.update (duration);
|
||||
|
||||
mSkyManager->update(duration);
|
||||
|
||||
mRendering.update(duration);
|
||||
}
|
||||
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
|
||||
if(store->cell->data.flags & store->cell->HasWater){
|
||||
if(mWater == 0)
|
||||
mWater = new MWRender::Water(rend.getCamera(), store->cell);
|
||||
mWater = new MWRender::Water(mRendering.getCamera(), store->cell);
|
||||
else
|
||||
mWater->changeCell(store->cell);
|
||||
//else
|
||||
|
@ -145,27 +166,32 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
|
|||
|
||||
void RenderingManager::skyEnable ()
|
||||
{
|
||||
if(mSkyManager)
|
||||
mSkyManager->enable();
|
||||
}
|
||||
|
||||
void RenderingManager::skyDisable ()
|
||||
{
|
||||
mSkyManager->disable();
|
||||
if(mSkyManager)
|
||||
mSkyManager->disable();
|
||||
}
|
||||
|
||||
void RenderingManager::skySetHour (double hour)
|
||||
{
|
||||
mSkyManager->setHour(hour);
|
||||
if(mSkyManager)
|
||||
mSkyManager->setHour(hour);
|
||||
}
|
||||
|
||||
|
||||
void RenderingManager::skySetDate (int day, int month)
|
||||
{
|
||||
mSkyManager->setDate(day, month);
|
||||
if(mSkyManager)
|
||||
mSkyManager->setDate(day, month);
|
||||
}
|
||||
|
||||
int RenderingManager::skyGetMasserPhase() const
|
||||
{
|
||||
|
||||
return mSkyManager->getMasserPhase();
|
||||
}
|
||||
|
||||
|
@ -174,12 +200,28 @@ int RenderingManager::skyGetSecundaPhase() const
|
|||
return mSkyManager->getSecundaPhase();
|
||||
}
|
||||
|
||||
void RenderingManager::skySetMoonColour (bool red)
|
||||
{
|
||||
mSkyManager->setMoonColour(red);
|
||||
void RenderingManager::skySetMoonColour (bool red){
|
||||
if(mSkyManager)
|
||||
mSkyManager->setMoonColour(red);
|
||||
}
|
||||
bool RenderingManager::toggleRenderMode(int mode){
|
||||
return mDebugging.toggleRenderMode(mode);
|
||||
|
||||
bool RenderingManager::toggleRenderMode(int mode)
|
||||
{
|
||||
if (mode == MWWorld::World::Render_CollisionDebug)
|
||||
return mDebugging.toggleRenderMode(mode);
|
||||
else // if (mode == MWWorld::World::Render_Wireframe)
|
||||
{
|
||||
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
|
||||
{
|
||||
mRendering.getCamera()->setPolygonMode(PM_WIREFRAME);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRendering.getCamera()->setPolygonMode(PM_SOLID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
|
||||
|
@ -187,31 +229,44 @@ void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
|
|||
Ogre::ColourValue color;
|
||||
color.setAsABGR (mCell.cell->ambi.fog);
|
||||
|
||||
float high = 4500 + 9000 * (1-mCell.cell->ambi.fogDensity);
|
||||
float low = 200;
|
||||
|
||||
rend.getScene()->setFog (FOG_LINEAR, color, 0, low, high);
|
||||
rend.getCamera()->setFarClipDistance (high + 10);
|
||||
rend.getViewport()->setBackgroundColour (color);
|
||||
configureFog(mCell.cell->ambi.fogDensity, color);
|
||||
}
|
||||
|
||||
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
|
||||
{
|
||||
/// \todo make the viewing distance and fog start/end configurable
|
||||
|
||||
// right now we load 3x3 cells, so the maximum viewing distance we
|
||||
// can allow (to prevent objects suddenly popping up) equals:
|
||||
// 8192 * 0.69
|
||||
// ^ cell size ^ minimum density value used (clear weather)
|
||||
float low = 5652.48 / density / 2.f;
|
||||
float high = 5652.48 / density;
|
||||
|
||||
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
|
||||
|
||||
mRendering.getCamera()->setFarClipDistance ( high );
|
||||
mRendering.getViewport()->setBackgroundColour (colour);
|
||||
}
|
||||
|
||||
|
||||
void RenderingManager::setAmbientMode()
|
||||
{
|
||||
switch (mAmbientMode)
|
||||
{
|
||||
case 0:
|
||||
|
||||
rend.getScene()->setAmbientLight(mAmbientColor);
|
||||
mRendering.getScene()->setAmbientLight(mAmbientColor);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
rend.getScene()->setAmbientLight(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1));
|
||||
mRendering.getScene()->setAmbientLight(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
rend.getScene()->setAmbientLight(ColourValue(1,1,1));
|
||||
mRendering.getScene()->setAmbientLight(ColourValue(1,1,1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -223,12 +278,15 @@ void RenderingManager::configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell
|
|||
|
||||
// Create a "sun" that shines light downwards. It doesn't look
|
||||
// completely right, but leave it for now.
|
||||
Ogre::Light *light = rend.getScene()->createLight();
|
||||
if(!mSun)
|
||||
{
|
||||
mSun = mRendering.getScene()->createLight();
|
||||
}
|
||||
Ogre::ColourValue colour;
|
||||
colour.setAsABGR (mCell.cell->ambi.sunlight);
|
||||
light->setDiffuseColour (colour);
|
||||
light->setType(Ogre::Light::LT_DIRECTIONAL);
|
||||
light->setDirection(0,-1,0);
|
||||
mSun->setDiffuseColour (colour);
|
||||
mSun->setType(Ogre::Light::LT_DIRECTIONAL);
|
||||
mSun->setDirection(0,-1,0);
|
||||
}
|
||||
// Switch through lighting modes.
|
||||
|
||||
|
@ -254,6 +312,49 @@ void RenderingManager::checkUnderwater(float y){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
|
||||
int mode, int number)
|
||||
{
|
||||
mActors.playAnimationGroup(ptr, groupName, mode, number);
|
||||
}
|
||||
|
||||
void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mActors.skipAnimation(ptr);
|
||||
}
|
||||
|
||||
void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
|
||||
{
|
||||
mSun->setDiffuseColour(colour);
|
||||
}
|
||||
|
||||
void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
|
||||
{
|
||||
mRendering.getScene()->setAmbientLight(colour);
|
||||
}
|
||||
|
||||
void RenderingManager::sunEnable()
|
||||
{
|
||||
if (mSun) mSun->setVisible(true);
|
||||
}
|
||||
|
||||
void RenderingManager::sunDisable()
|
||||
{
|
||||
if (mSun) mSun->setVisible(false);
|
||||
}
|
||||
|
||||
void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
|
||||
{
|
||||
// direction * -1 (because 'direction' is camera to sun vector and not sun to camera),
|
||||
// then convert from MW to ogre coordinates (swap y,z and make y negative)
|
||||
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y));
|
||||
|
||||
mSkyManager->setSunDirection(direction);
|
||||
}
|
||||
|
||||
void RenderingManager::setGlare(bool glare)
|
||||
{
|
||||
mSkyManager->setGlare(glare);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <utility>
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include <openengine/ogre/fader.hpp>
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
@ -19,9 +20,9 @@
|
|||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "renderinginterface.hpp"
|
||||
#include "npcs.hpp"
|
||||
#include "creatures.hpp"
|
||||
|
||||
#include "objects.hpp"
|
||||
#include "actors.hpp"
|
||||
#include "player.hpp"
|
||||
#include "water.hpp"
|
||||
|
||||
|
@ -50,12 +51,12 @@ class RenderingManager: private RenderingInterface {
|
|||
|
||||
private:
|
||||
|
||||
virtual MWRender::Npcs& getNPCs();
|
||||
virtual MWRender::Creatures& getCreatures();
|
||||
|
||||
virtual MWRender::Objects& getObjects();
|
||||
virtual MWRender::Actors& getActors();
|
||||
|
||||
public:
|
||||
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine);
|
||||
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment);
|
||||
virtual ~RenderingManager();
|
||||
|
||||
|
||||
|
@ -64,8 +65,12 @@ class RenderingManager: private RenderingInterface {
|
|||
/// MWWorld::Player has been rewritten to not need access
|
||||
/// to internal details of the rendering system anymore
|
||||
|
||||
SkyManager* getSkyManager();
|
||||
|
||||
void toggleLight();
|
||||
bool toggleRenderMode(int mode);
|
||||
|
||||
OEngine::Render::Fader* getFader();
|
||||
|
||||
void removeCell (MWWorld::Ptr::CellStore *store);
|
||||
|
||||
|
@ -89,7 +94,14 @@ class RenderingManager: private RenderingInterface {
|
|||
void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store);
|
||||
|
||||
void update (float duration);
|
||||
|
||||
|
||||
void setAmbientColour(const Ogre::ColourValue& colour);
|
||||
void setSunColour(const Ogre::ColourValue& colour);
|
||||
void setSunDirection(const Ogre::Vector3& direction);
|
||||
void sunEnable();
|
||||
void sunDisable();
|
||||
|
||||
void setGlare(bool glare);
|
||||
void skyEnable ();
|
||||
void skyDisable ();
|
||||
void skySetHour (double hour);
|
||||
|
@ -98,34 +110,55 @@ class RenderingManager: private RenderingInterface {
|
|||
int skyGetSecundaPhase() const;
|
||||
void skySetMoonColour (bool red);
|
||||
void configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell);
|
||||
|
||||
/// configure fog according to cell
|
||||
void configureFog(ESMS::CellStore<MWWorld::RefData> &mCell);
|
||||
|
||||
/// configure fog manually
|
||||
void configureFog(const float density, const Ogre::ColourValue& colour);
|
||||
|
||||
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
|
||||
int number = 1);
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the rendered scene should be ignored.
|
||||
///
|
||||
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param number How offen the animation should be run
|
||||
|
||||
void skipAnimation (const MWWorld::Ptr& ptr);
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the rendered scene should be ignored.
|
||||
|
||||
private:
|
||||
|
||||
void setAmbientMode();
|
||||
|
||||
SkyManager* mSkyManager;
|
||||
OEngine::Render::OgreRenderer &rend;
|
||||
Ogre::Camera* camera;
|
||||
MWRender::Npcs npcs;
|
||||
MWRender::Creatures creatures;
|
||||
MWRender::Water *mWater;
|
||||
MWRender::Objects objects;
|
||||
|
||||
Ogre::Camera* camera;
|
||||
MWRender::Water *mWater;
|
||||
|
||||
|
||||
|
||||
OEngine::Render::OgreRenderer &mRendering;
|
||||
|
||||
MWRender::Objects mObjects;
|
||||
MWRender::Actors mActors;
|
||||
|
||||
|
||||
// 0 normal, 1 more bright, 2 max
|
||||
int mAmbientMode;
|
||||
|
||||
Ogre::ColourValue mAmbientColor;
|
||||
Ogre::Light* mSun;
|
||||
|
||||
/// Root node for all objects added to the scene. This is rotated so
|
||||
/// that the OGRE coordinate system matches that used internally in
|
||||
/// Morrowind.
|
||||
Ogre::SceneNode *mwRoot;
|
||||
Ogre::SceneNode *mMwRoot;
|
||||
Ogre::RaySceneQuery *mRaySceneQuery;
|
||||
|
||||
OEngine::Physic::PhysicEngine* eng;
|
||||
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
||||
|
||||
MWRender::Player *mPlayer;
|
||||
MWRender::Debugging mDebugging;
|
||||
|
|
|
@ -1,116 +1,783 @@
|
|||
#include "sky.hpp"
|
||||
#include "Caelum.h"
|
||||
|
||||
namespace MWRender
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreMesh.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreHardwareVertexBuffer.h>
|
||||
#include <OgreHighLevelGpuProgramManager.h>
|
||||
|
||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
using namespace MWRender;
|
||||
using namespace Ogre;
|
||||
|
||||
BillboardObject::BillboardObject( const String& textureName,
|
||||
const float initialSize,
|
||||
const Vector3& position,
|
||||
SceneNode* rootNode)
|
||||
{
|
||||
//
|
||||
// Implements a Caelum sky with default settings.
|
||||
//
|
||||
// Note: this is intended as a temporary solution to provide some form of
|
||||
// sky rendering. This code will obviously need significant tailoring to
|
||||
// support fidelity with Morrowind's rendering. Before doing major work
|
||||
// on this class, more research should be done to determine whether
|
||||
// Caelum or another plug-in such as SkyX would be best for the long-term.
|
||||
//
|
||||
class CaelumManager : public SkyManager
|
||||
init(textureName, initialSize, position, rootNode);
|
||||
}
|
||||
|
||||
BillboardObject::BillboardObject()
|
||||
{
|
||||
}
|
||||
|
||||
void BillboardObject::setVisible(const bool visible)
|
||||
{
|
||||
mNode->setVisible(visible);
|
||||
}
|
||||
|
||||
void BillboardObject::setSize(const float size)
|
||||
{
|
||||
mNode->setScale(size, size, size);
|
||||
}
|
||||
|
||||
void BillboardObject::setVisibility(const float visibility)
|
||||
{
|
||||
mMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, visibility);
|
||||
}
|
||||
|
||||
void BillboardObject::setPosition(const Vector3& pPosition)
|
||||
{
|
||||
Vector3 normalised = pPosition.normalisedCopy();
|
||||
Vector3 finalPosition = normalised * 1000.f;
|
||||
|
||||
mBBSet->setCommonDirection( -normalised );
|
||||
|
||||
mNode->setPosition(finalPosition);
|
||||
}
|
||||
|
||||
Vector3 BillboardObject::getPosition() const
|
||||
{
|
||||
Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition();
|
||||
return Vector3(p.x, -p.z, p.y);
|
||||
}
|
||||
|
||||
void BillboardObject::setColour(const ColourValue& pColour)
|
||||
{
|
||||
mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour);
|
||||
}
|
||||
|
||||
void BillboardObject::setRenderQueue(unsigned int id)
|
||||
{
|
||||
mBBSet->setRenderQueueGroup(id);
|
||||
}
|
||||
|
||||
SceneNode* BillboardObject::getNode()
|
||||
{
|
||||
return mNode;
|
||||
}
|
||||
|
||||
void BillboardObject::init(const String& textureName,
|
||||
const float initialSize,
|
||||
const Vector3& position,
|
||||
SceneNode* rootNode)
|
||||
{
|
||||
SceneManager* sceneMgr = rootNode->getCreator();
|
||||
|
||||
Vector3 finalPosition = position.normalisedCopy() * 1000.f;
|
||||
|
||||
static unsigned int bodyCount=0;
|
||||
|
||||
/// \todo These billboards are not 100% correct, might want to revisit them later
|
||||
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
||||
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
|
||||
mBBSet->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+2);
|
||||
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
|
||||
mBBSet->setCommonDirection( -position.normalisedCopy() );
|
||||
mNode = rootNode->createChildSceneNode();
|
||||
mNode->setPosition(finalPosition);
|
||||
mNode->attachObject(mBBSet);
|
||||
mBBSet->createBillboard(0,0,0);
|
||||
|
||||
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
mMaterial->removeAllTechniques();
|
||||
Pass* p = mMaterial->createTechnique()->createPass();
|
||||
p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
p->setDepthCheckEnabled(false);
|
||||
p->setDepthWriteEnabled(false);
|
||||
p->setSelfIllumination(1.0,1.0,1.0);
|
||||
p->setDiffuse(0.0,0.0,0.0,1.0);
|
||||
p->setAmbient(0.0,0.0,0.0);
|
||||
p->createTextureUnitState(textureName);
|
||||
mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount));
|
||||
|
||||
bodyCount++;
|
||||
}
|
||||
|
||||
Moon::Moon( const String& textureName,
|
||||
const float initialSize,
|
||||
const Vector3& position,
|
||||
SceneNode* rootNode)
|
||||
{
|
||||
init(textureName, initialSize, position, rootNode);
|
||||
|
||||
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||
HighLevelGpuProgramPtr vshader;
|
||||
if (mgr.resourceExists("Moon_VP"))
|
||||
vshader = mgr.getByName("Moon_VP");
|
||||
else
|
||||
vshader = mgr.createProgram("Moon_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM);
|
||||
vshader->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader->setParameter("entry_point", "main_vp");
|
||||
StringUtil::StrStreamType outStream;
|
||||
outStream <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float2 oUV : TEXCOORD0, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oUV = uv; \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
"}";
|
||||
vshader->setSource(outStream.str());
|
||||
vshader->load();
|
||||
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
|
||||
|
||||
HighLevelGpuProgramPtr fshader;
|
||||
if (mgr.resourceExists("Moon_FP"))
|
||||
fshader = mgr.getByName("Moon_FP");
|
||||
else
|
||||
fshader = mgr.createProgram("Moon_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM);
|
||||
|
||||
fshader->setParameter("profiles", "ps_2_x arbfp1");
|
||||
fshader->setParameter("entry_point", "main_fp");
|
||||
StringUtil::StrStreamType outStream2;
|
||||
outStream2 <<
|
||||
"void main_fp( \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||
" uniform float4 skyColour, \n"
|
||||
" uniform float4 diffuse, \n"
|
||||
" uniform float4 emissive \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" float4 tex = tex2D(texture, uv); \n"
|
||||
" oColor = float4(emissive.xyz,1) * tex; \n"
|
||||
// use a circle for the alpha (compute UV distance to center)
|
||||
// looks a bit bad because its not filtered on the edges,
|
||||
// but it's cheaper than a seperate alpha texture.
|
||||
" float sqrUVdist = pow(uv.x-0.5,2) + pow(uv.y-0.5, 2); \n"
|
||||
" oColor.a = diffuse.a * (sqrUVdist >= 0.24 ? 0 : 1); \n"
|
||||
" oColor.rgb += (1-tex.a) * oColor.a * skyColour.rgb; \n"//fill dark side of moon with skycolour
|
||||
" oColor.rgb += (1-diffuse.a) * skyColour.rgb; \n"//fade bump
|
||||
"}";
|
||||
fshader->setSource(outStream2.str());
|
||||
fshader->load();
|
||||
fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
|
||||
|
||||
setVisibility(1.0);
|
||||
|
||||
mPhase = Moon::Phase_Full;
|
||||
}
|
||||
|
||||
void Moon::setType(const Moon::Type& type)
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
void Moon::setSkyColour(const Ogre::ColourValue& colour)
|
||||
{
|
||||
mMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("skyColour", colour);
|
||||
}
|
||||
|
||||
void Moon::setPhase(const Moon::Phase& phase)
|
||||
{
|
||||
// Colour texture
|
||||
Ogre::String textureName = "textures\\tx_";
|
||||
|
||||
if (mType == Moon::Type_Secunda) textureName += "secunda_";
|
||||
else textureName += "masser_";
|
||||
|
||||
if (phase == Moon::Phase_New) textureName += "new";
|
||||
else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax";
|
||||
else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax";
|
||||
else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax";
|
||||
else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan";
|
||||
else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan";
|
||||
else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan";
|
||||
else if (phase == Moon::Phase_Full) textureName += "full";
|
||||
|
||||
textureName += ".dds";
|
||||
|
||||
mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(textureName);
|
||||
|
||||
mPhase = phase;
|
||||
}
|
||||
|
||||
Moon::Phase Moon::getPhase() const
|
||||
{
|
||||
return mPhase;
|
||||
}
|
||||
|
||||
unsigned int Moon::getPhaseInt() const
|
||||
{
|
||||
if (mPhase == Moon::Phase_New) return 0;
|
||||
else if (mPhase == Moon::Phase_WaxingCrescent) return 1;
|
||||
else if (mPhase == Moon::Phase_WaningCrescent) return 1;
|
||||
else if (mPhase == Moon::Phase_WaxingHalf) return 2;
|
||||
else if (mPhase == Moon::Phase_WaningHalf) return 2;
|
||||
else if (mPhase == Moon::Phase_WaxingGibbous) return 3;
|
||||
else if (mPhase == Moon::Phase_WaningGibbous) return 3;
|
||||
else if (mPhase == Moon::Phase_Full) return 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
|
||||
{
|
||||
// Get the vertex colour buffer of this mesh
|
||||
const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE );
|
||||
HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource());
|
||||
|
||||
// Lock
|
||||
void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL);
|
||||
|
||||
// Iterate over all vertices
|
||||
int vertex_size = colourBuffer->getVertexSize();
|
||||
float * currentVertex = NULL;
|
||||
for (unsigned int i=0; i<colourBuffer->getNumVertices(); ++i)
|
||||
{
|
||||
protected:
|
||||
Caelum::CaelumSystem* mpCaelumSystem;
|
||||
// Get a pointer to the vertex colour
|
||||
ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex );
|
||||
|
||||
public:
|
||||
CaelumManager (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir);
|
||||
virtual ~CaelumManager ();
|
||||
|
||||
virtual void enable() {}
|
||||
|
||||
virtual void disable() {}
|
||||
|
||||
virtual void setHour (double hour) {}
|
||||
///< will be called even when sky is disabled.
|
||||
|
||||
virtual void setDate (int day, int month) {}
|
||||
///< will be called even when sky is disabled.
|
||||
|
||||
virtual int getMasserPhase() const { return 0; }
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
|
||||
virtual int getSecundaPhase() const { return 0; }
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
|
||||
virtual void setMoonColour (bool red) {}
|
||||
};
|
||||
|
||||
CaelumManager::CaelumManager (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir)
|
||||
: mpCaelumSystem (NULL)
|
||||
{
|
||||
using namespace Ogre;
|
||||
using namespace Caelum;
|
||||
|
||||
assert(pCamera);
|
||||
assert(pRenderWindow);
|
||||
|
||||
// Load the Caelum resources
|
||||
//
|
||||
ResourceGroupManager::getSingleton().addResourceLocation((resDir / "caelum").string(), "FileSystem", "Caelum");
|
||||
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
||||
|
||||
// Load the Caelum resources
|
||||
//
|
||||
Ogre::SceneManager* pScene = pCamera->getSceneManager();
|
||||
Caelum::CaelumSystem::CaelumComponent componentMask = CaelumSystem::CAELUM_COMPONENTS_DEFAULT;
|
||||
mpCaelumSystem = new Caelum::CaelumSystem (Root::getSingletonPtr(), pScene, componentMask);
|
||||
|
||||
// Set time acceleration.
|
||||
mpCaelumSystem->getUniversalClock()->setTimeScale(128);
|
||||
|
||||
// Disable fog since OpenMW is handling OGRE fog elsewhere
|
||||
mpCaelumSystem->setManageSceneFog(false);
|
||||
|
||||
// Change the camera far distance to make sure the sky is not clipped
|
||||
pCamera->setFarClipDistance(50000);
|
||||
|
||||
// Register Caelum as an OGRE listener
|
||||
pRenderWindow->addListener(mpCaelumSystem);
|
||||
Root::getSingletonPtr()->addFrameListener(mpCaelumSystem);
|
||||
}
|
||||
|
||||
CaelumManager::~CaelumManager()
|
||||
{
|
||||
if (mpCaelumSystem)
|
||||
mpCaelumSystem->shutdown (false);
|
||||
}
|
||||
|
||||
/// Creates and connects the sky rendering component to OGRE.
|
||||
///
|
||||
/// \return NULL on failure.
|
||||
///
|
||||
SkyManager* SkyManager::create (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir)
|
||||
{
|
||||
SkyManager* pSkyManager = NULL;
|
||||
|
||||
try
|
||||
unsigned char alpha;
|
||||
if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row
|
||||
else if (meshType == 1)
|
||||
{
|
||||
pSkyManager = new CaelumManager(pRenderWindow, pCamera, resDir);
|
||||
}
|
||||
catch (Ogre::Exception& e)
|
||||
{
|
||||
std::cout << "\nOGRE Exception when attempting to add sky: "
|
||||
<< e.getFullDescription().c_str() << std::endl;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "\nException when attempting to add sky: "
|
||||
<< e.what() << std::endl;
|
||||
if (i>= 49 && i <= 64) alpha = 0; // bottom-most row
|
||||
else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row
|
||||
else alpha = 255;
|
||||
}
|
||||
|
||||
return pSkyManager;
|
||||
uint8 tmpR = static_cast<uint8>(255);
|
||||
uint8 tmpG = static_cast<uint8>(255);
|
||||
uint8 tmpB = static_cast<uint8>(255);
|
||||
uint8 tmpA = static_cast<uint8>(alpha);
|
||||
|
||||
// This does not matter since R and B are always 1.
|
||||
/*VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();
|
||||
switch (format)
|
||||
{
|
||||
case VET_COLOUR_ARGB:
|
||||
std::swap(tmpR, tmpB);
|
||||
break;
|
||||
case VET_COLOUR_ABGR:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}*/
|
||||
|
||||
// Modify
|
||||
*((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
|
||||
|
||||
// Move to the next vertex
|
||||
pData = static_cast<unsigned char *> (pData) + vertex_size;
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock
|
||||
ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock();
|
||||
}
|
||||
|
||||
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env) :
|
||||
mGlareFade(0), mGlareEnabled(false)
|
||||
{
|
||||
mEnvironment = env;
|
||||
mViewport = pCamera->getViewport();
|
||||
mSceneMgr = pMwRoot->getCreator();
|
||||
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
|
||||
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
|
||||
mRootNode->setInheritOrientation(false);
|
||||
|
||||
/// \todo preload all the textures and meshes that are used for sky rendering
|
||||
|
||||
// Create overlay used for thunderstorm
|
||||
MaterialPtr material = MaterialManager::getSingleton().create( "ThunderMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
|
||||
Pass* pass = material->getTechnique(0)->getPass(0);
|
||||
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
mThunderTextureUnit = pass->createTextureUnitState();
|
||||
mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f));
|
||||
mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f);
|
||||
OverlayManager& ovm = OverlayManager::getSingleton();
|
||||
mThunderOverlay = ovm.create( "ThunderOverlay" );
|
||||
OverlayContainer* overlay_panel;
|
||||
overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", "ThunderPanel");
|
||||
overlay_panel->_setPosition(0, 0);
|
||||
overlay_panel->_setDimensions(1, 1);
|
||||
overlay_panel->setMaterialName( "ThunderMaterial" );
|
||||
overlay_panel->show();
|
||||
mThunderOverlay->add2D(overlay_panel);
|
||||
mThunderOverlay->hide();
|
||||
|
||||
mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
||||
mSecunda->setType(Moon::Type_Secunda);
|
||||
mSecunda->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+4);
|
||||
|
||||
mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
||||
mMasser->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+3);
|
||||
mMasser->setType(Moon::Type_Masser);
|
||||
|
||||
mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode);
|
||||
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode);
|
||||
mSunGlare->setRenderQueue(RENDER_QUEUE_SKIES_LATE);
|
||||
|
||||
|
||||
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||
|
||||
// Stars
|
||||
/// \todo sky_night_02.nif (available in Bloodmoon)
|
||||
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
|
||||
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
|
||||
night1_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+1);
|
||||
|
||||
mAtmosphereNight = mRootNode->createChildSceneNode();
|
||||
mAtmosphereNight->attachObject(night1_ent);
|
||||
|
||||
// Stars vertex shader
|
||||
HighLevelGpuProgramPtr stars_vp = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_VERTEX_PROGRAM);
|
||||
stars_vp->setParameter("profiles", "vs_2_x arbvp1");
|
||||
stars_vp->setParameter("entry_point", "main_vp");
|
||||
StringUtil::StrStreamType outStream4;
|
||||
outStream4 <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float2 oUV : TEXCOORD0, \n"
|
||||
" out float oFade : TEXCOORD1, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oUV = uv; \n"
|
||||
" oFade = (position.z > 50) ? 1.f : 0.f; \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
"}";
|
||||
stars_vp->setSource(outStream4.str());
|
||||
stars_vp->load();
|
||||
stars_vp->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
|
||||
// Stars fragment shader
|
||||
HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_FRAGMENT_PROGRAM);
|
||||
stars_fp->setParameter("profiles", "ps_2_x arbfp1");
|
||||
stars_fp->setParameter("entry_point", "main_fp");
|
||||
StringUtil::StrStreamType outStream5;
|
||||
outStream5 <<
|
||||
"void main_fp( \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" in float fade : TEXCOORD1, \n"
|
||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||
" uniform float opacity, \n"
|
||||
" uniform float4 diffuse, \n"
|
||||
" uniform float4 emissive \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n"
|
||||
"}";
|
||||
stars_fp->setSource(outStream5.str());
|
||||
stars_fp->load();
|
||||
stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||
|
||||
for (unsigned int i=0; i<night1_ent->getNumSubEntities(); ++i)
|
||||
{
|
||||
MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial();
|
||||
mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
|
||||
mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0);
|
||||
mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0);
|
||||
mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
|
||||
mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
|
||||
mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName());
|
||||
mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName());
|
||||
mStarsMaterials[i] = mp;
|
||||
}
|
||||
|
||||
// Atmosphere (day)
|
||||
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
|
||||
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
|
||||
|
||||
ModVertexAlpha(atmosphere_ent, 0);
|
||||
|
||||
atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY);
|
||||
mAtmosphereDay = mRootNode->createChildSceneNode();
|
||||
mAtmosphereDay->attachObject(atmosphere_ent);
|
||||
mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial();
|
||||
|
||||
// Atmosphere shader
|
||||
HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_VERTEX_PROGRAM);
|
||||
|
||||
vshader->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader->setParameter("entry_point", "main_vp");
|
||||
|
||||
StringUtil::StrStreamType outStream;
|
||||
outStream <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float4 color : COLOR, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" uniform float4 emissive, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
" oColor = color * emissive; \n"
|
||||
"}";
|
||||
vshader->setSource(outStream.str());
|
||||
vshader->load();
|
||||
|
||||
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
vshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
|
||||
|
||||
// Clouds
|
||||
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
|
||||
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
|
||||
clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5);
|
||||
SceneNode* clouds_node = mRootNode->createChildSceneNode();
|
||||
clouds_node->attachObject(clouds_ent);
|
||||
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
|
||||
|
||||
// Clouds vertex shader
|
||||
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_VERTEX_PROGRAM);
|
||||
vshader2->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader2->setParameter("entry_point", "main_vp");
|
||||
StringUtil::StrStreamType outStream3;
|
||||
outStream3 <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float4 color : COLOR, \n"
|
||||
" out float4 oColor : TEXCOORD1, \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float2 oUV : TEXCOORD0, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oUV = uv; \n"
|
||||
" oColor = color; \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
"}";
|
||||
vshader2->setSource(outStream3.str());
|
||||
vshader2->load();
|
||||
vshader2->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader2->getName());
|
||||
|
||||
// Clouds fragment shader
|
||||
mCloudFragmentShader = mgr.createProgram("Clouds_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_FRAGMENT_PROGRAM);
|
||||
mCloudFragmentShader->setParameter("profiles", "ps_2_x arbfp1");
|
||||
mCloudFragmentShader->setParameter("entry_point", "main_fp");
|
||||
StringUtil::StrStreamType outStream2;
|
||||
outStream2 <<
|
||||
"void main_fp( \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" in float4 color : TEXCOORD1, \n"
|
||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||
" uniform sampler2D secondTexture : TEXUNIT1, \n"
|
||||
" uniform float transitionFactor, \n"
|
||||
" uniform float time, \n"
|
||||
" uniform float speed, \n"
|
||||
" uniform float opacity, \n"
|
||||
" uniform float4 emissive \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" uv += float2(1,0) * time * speed * 0.003; \n" // Scroll in x direction
|
||||
" float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n"
|
||||
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"
|
||||
"}";
|
||||
mCloudFragmentShader->setSource(outStream2.str());
|
||||
mCloudFragmentShader->load();
|
||||
mCloudFragmentShader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(mCloudFragmentShader->getName());
|
||||
setCloudsOpacity(0.75);
|
||||
|
||||
ModVertexAlpha(clouds_ent, 1);
|
||||
|
||||
// I'm not sure if the materials are being used by any other objects
|
||||
// Make a unique "modifiable" copy of the materials to be sure
|
||||
mCloudMaterial = mCloudMaterial->clone("Clouds");
|
||||
clouds_ent->getSubEntity(0)->setMaterial(mCloudMaterial);
|
||||
mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere");
|
||||
atmosphere_ent->getSubEntity(0)->setMaterial(mAtmosphereMaterial);
|
||||
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.0);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
|
||||
}
|
||||
|
||||
SkyManager::~SkyManager()
|
||||
{
|
||||
delete mSun;
|
||||
delete mSunGlare;
|
||||
delete mMasser;
|
||||
delete mSecunda;
|
||||
}
|
||||
|
||||
int SkyManager::getMasserPhase() const
|
||||
{
|
||||
return mMasser->getPhaseInt();
|
||||
}
|
||||
|
||||
int SkyManager::getSecundaPhase() const
|
||||
{
|
||||
return mSecunda->getPhaseInt();
|
||||
}
|
||||
|
||||
void SkyManager::update(float duration)
|
||||
{
|
||||
if (!mEnabled) return;
|
||||
|
||||
// UV Scroll the clouds
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", mEnvironment->mWorld->getTimeScaleFactor()/30.f);
|
||||
|
||||
/// \todo improve this
|
||||
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||
|
||||
// increase the strength of the sun glare effect depending
|
||||
// on how directly the player is looking at the sun
|
||||
if (mSunEnabled)
|
||||
{
|
||||
Vector3 sun = mSunGlare->getPosition();
|
||||
sun = Vector3(sun.x, sun.z, -sun.y);
|
||||
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
||||
const Degree angle = sun.angleBetween( cam );
|
||||
float val = 1- (angle.valueDegrees() / 180.f);
|
||||
val = (val*val*val*val)*2;
|
||||
|
||||
if (mGlareEnabled)
|
||||
{
|
||||
mGlareFade += duration*3;
|
||||
if (mGlareFade > 1) mGlareFade = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mGlareFade -= duration*3;
|
||||
if (mGlareFade < 0.3) mGlareFade = 0;
|
||||
}
|
||||
|
||||
mSunGlare->setSize(val * (mGlareFade));
|
||||
}
|
||||
|
||||
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
|
||||
mSun->setVisible(mSunEnabled);
|
||||
mMasser->setVisible(mMasserEnabled);
|
||||
mSecunda->setVisible(mSecundaEnabled);
|
||||
|
||||
// rotate the stars by 360 degrees every 4 days
|
||||
mAtmosphereNight->roll(Degree(mEnvironment->mWorld->getTimeScaleFactor()*duration*360 / (3600*96.f)));
|
||||
}
|
||||
|
||||
void SkyManager::enable()
|
||||
{
|
||||
mRootNode->setVisible(true);
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::disable()
|
||||
{
|
||||
mRootNode->setVisible(false);
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::setMoonColour (bool red)
|
||||
{
|
||||
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
|
||||
: ColourValue(1.0, 1.0, 1.0));
|
||||
}
|
||||
|
||||
void SkyManager::setCloudsOpacity(float opacity)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity));
|
||||
}
|
||||
|
||||
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
||||
{
|
||||
if (mClouds != weather.mCloudTexture)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture);
|
||||
mClouds = weather.mCloudTexture;
|
||||
}
|
||||
|
||||
if (mNextClouds != weather.mNextCloudTexture)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("textures\\"+weather.mNextCloudTexture);
|
||||
mNextClouds = weather.mNextCloudTexture;
|
||||
}
|
||||
|
||||
if (mCloudBlendFactor != weather.mCloudBlendFactor)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("transitionFactor", Real(weather.mCloudBlendFactor));
|
||||
mCloudBlendFactor = weather.mCloudBlendFactor;
|
||||
}
|
||||
|
||||
if (mCloudOpacity != weather.mCloudOpacity)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(weather.mCloudOpacity));
|
||||
mCloudOpacity = weather.mCloudOpacity;
|
||||
}
|
||||
|
||||
if (mCloudColour != weather.mSunColor)
|
||||
{
|
||||
ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7,
|
||||
weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7,
|
||||
weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7);
|
||||
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(clr);
|
||||
mCloudColour = weather.mSunColor;
|
||||
}
|
||||
|
||||
if (mSkyColour != weather.mSkyColor)
|
||||
{
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor);
|
||||
mMasser->setSkyColour(weather.mSkyColor);
|
||||
mSecunda->setSkyColour(weather.mSkyColor);
|
||||
mSkyColour = weather.mSkyColor;
|
||||
}
|
||||
|
||||
if (mCloudSpeed != weather.mCloudSpeed)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("speed", Real(weather.mCloudSpeed));
|
||||
mCloudSpeed = weather.mCloudSpeed;
|
||||
}
|
||||
|
||||
if (weather.mNight && mStarsOpacity != weather.mNightFade)
|
||||
{
|
||||
if (weather.mNightFade == 0)
|
||||
mAtmosphereNight->setVisible(false);
|
||||
else
|
||||
{
|
||||
mAtmosphereNight->setVisible(true);
|
||||
for (int i=0; i<7; ++i)
|
||||
mStarsMaterials[i]->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade);
|
||||
mStarsOpacity = weather.mNightFade;
|
||||
}
|
||||
}
|
||||
|
||||
float strength;
|
||||
float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length());
|
||||
if (timeofday_angle <= 0.44)
|
||||
strength = timeofday_angle/0.44f;
|
||||
else
|
||||
strength = 1.f;
|
||||
|
||||
mSunGlare->setVisibility(weather.mGlareView * strength);
|
||||
mSun->setVisibility(strength);
|
||||
|
||||
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
||||
}
|
||||
|
||||
void SkyManager::setGlare(bool glare)
|
||||
{
|
||||
mGlareEnabled = glare;
|
||||
}
|
||||
|
||||
Vector3 SkyManager::getRealSunPos()
|
||||
{
|
||||
return mSun->getNode()->_getDerivedPosition();
|
||||
}
|
||||
|
||||
void SkyManager::sunEnable()
|
||||
{
|
||||
mSunEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::sunDisable()
|
||||
{
|
||||
mSunEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::setSunDirection(const Vector3& direction)
|
||||
{
|
||||
mSun->setPosition(direction);
|
||||
mSunGlare->setPosition(direction);
|
||||
}
|
||||
|
||||
void SkyManager::setMasserDirection(const Vector3& direction)
|
||||
{
|
||||
mMasser->setPosition(direction);
|
||||
}
|
||||
|
||||
void SkyManager::setSecundaDirection(const Vector3& direction)
|
||||
{
|
||||
mSecunda->setPosition(direction);
|
||||
}
|
||||
|
||||
void SkyManager::masserEnable()
|
||||
{
|
||||
mMasserEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::secundaEnable()
|
||||
{
|
||||
mSecundaEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::masserDisable()
|
||||
{
|
||||
mMasserEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::secundaDisable()
|
||||
{
|
||||
mSecundaEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::setThunder(const float factor)
|
||||
{
|
||||
if (factor > 0.f)
|
||||
{
|
||||
mThunderOverlay->show();
|
||||
mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, factor*0.6);
|
||||
}
|
||||
else
|
||||
mThunderOverlay->hide();
|
||||
}
|
||||
|
||||
void SkyManager::setMasserFade(const float fade)
|
||||
{
|
||||
mMasser->setVisibility(fade);
|
||||
}
|
||||
|
||||
void SkyManager::setSecundaFade(const float fade)
|
||||
{
|
||||
mSecunda->setVisibility(fade);
|
||||
}
|
||||
|
||||
void SkyManager::setHour(double hour)
|
||||
{
|
||||
mHour = hour;
|
||||
}
|
||||
|
||||
void SkyManager::setDate(int day, int month)
|
||||
{
|
||||
mDay = day;
|
||||
mMonth = month;
|
||||
}
|
||||
|
|
|
@ -1,40 +1,217 @@
|
|||
#ifndef _GAME_RENDER_SKY_H
|
||||
#define _GAME_RENDER_SKY_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <OgreVector3.h>
|
||||
#include <OgreString.h>
|
||||
#include <OgreMaterial.h>
|
||||
#include <OgreColourValue.h>
|
||||
#include <OgreHighLevelGpuProgram.h>
|
||||
|
||||
#include "sky.hpp"
|
||||
#include "../mwworld/weather.hpp"
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class RenderWindow;
|
||||
class SceneNode;
|
||||
class Camera;
|
||||
class Viewport;
|
||||
class SceneManager;
|
||||
class Entity;
|
||||
class BillboardSet;
|
||||
class TextureUnitState;
|
||||
class Overlay;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
///
|
||||
/// Interface for the sky rendering system
|
||||
///
|
||||
class BillboardObject
|
||||
{
|
||||
public:
|
||||
BillboardObject( const Ogre::String& textureName,
|
||||
const float size,
|
||||
const Ogre::Vector3& position,
|
||||
Ogre::SceneNode* rootNode
|
||||
);
|
||||
BillboardObject();
|
||||
|
||||
virtual ~BillboardObject() {}
|
||||
|
||||
void setColour(const Ogre::ColourValue& pColour);
|
||||
void setPosition(const Ogre::Vector3& pPosition);
|
||||
void setVisible(const bool visible);
|
||||
void setRenderQueue(unsigned int id);
|
||||
void setSize(const float size);
|
||||
Ogre::Vector3 getPosition() const;
|
||||
|
||||
void setVisibility(const float visibility);
|
||||
|
||||
Ogre::SceneNode* getNode();
|
||||
|
||||
protected:
|
||||
virtual void init(const Ogre::String& textureName,
|
||||
const float size,
|
||||
const Ogre::Vector3& position,
|
||||
Ogre::SceneNode* rootNode);
|
||||
|
||||
Ogre::SceneNode* mNode;
|
||||
Ogre::MaterialPtr mMaterial;
|
||||
Ogre::BillboardSet* mBBSet;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The moons need a seperate class because of their shader (which allows them to be partially transparent)
|
||||
*/
|
||||
class Moon : public BillboardObject
|
||||
{
|
||||
public:
|
||||
Moon( const Ogre::String& textureName,
|
||||
const float size,
|
||||
const Ogre::Vector3& position,
|
||||
Ogre::SceneNode* rootNode
|
||||
);
|
||||
|
||||
virtual ~Moon() {}
|
||||
|
||||
enum Phase
|
||||
{
|
||||
Phase_New = 0,
|
||||
Phase_WaxingCrescent,
|
||||
Phase_WaxingHalf,
|
||||
Phase_WaxingGibbous,
|
||||
Phase_Full,
|
||||
Phase_WaningGibbous,
|
||||
Phase_WaningHalf,
|
||||
Phase_WaningCrescent
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
Type_Masser = 0,
|
||||
Type_Secunda
|
||||
};
|
||||
|
||||
void setPhase(const Phase& phase);
|
||||
void setType(const Type& type);
|
||||
void setSkyColour(const Ogre::ColourValue& colour);
|
||||
|
||||
Phase getPhase() const;
|
||||
unsigned int getPhaseInt() const;
|
||||
|
||||
private:
|
||||
Type mType;
|
||||
Phase mPhase;
|
||||
};
|
||||
|
||||
class SkyManager
|
||||
{
|
||||
public:
|
||||
static SkyManager* create (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir);
|
||||
virtual ~SkyManager() {}
|
||||
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env);
|
||||
~SkyManager();
|
||||
|
||||
virtual void enable() = 0;
|
||||
void update(float duration);
|
||||
|
||||
virtual void disable() = 0;
|
||||
void enable();
|
||||
|
||||
virtual void setHour (double hour) = 0;
|
||||
void disable();
|
||||
|
||||
virtual void setDate (int day, int month) = 0;
|
||||
void setHour (double hour);
|
||||
///< will be called even when sky is disabled.
|
||||
|
||||
virtual int getMasserPhase() const = 0;
|
||||
void setDate (int day, int month);
|
||||
///< will be called even when sky is disabled.
|
||||
|
||||
virtual int getSecundaPhase() const = 0;
|
||||
int getMasserPhase() const;
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
|
||||
virtual void setMoonColour (bool red) = 0;
|
||||
int getSecundaPhase() const;
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
|
||||
void setMoonColour (bool red);
|
||||
///< change Secunda colour to red
|
||||
|
||||
void setCloudsOpacity(float opacity);
|
||||
///< change opacity of the clouds
|
||||
|
||||
void setWeather(const MWWorld::WeatherResult& weather);
|
||||
|
||||
void sunEnable();
|
||||
|
||||
void sunDisable();
|
||||
|
||||
void setSunDirection(const Ogre::Vector3& direction);
|
||||
|
||||
void setMasserDirection(const Ogre::Vector3& direction);
|
||||
|
||||
void setSecundaDirection(const Ogre::Vector3& direction);
|
||||
|
||||
void setMasserFade(const float fade);
|
||||
|
||||
void setSecundaFade(const float fade);
|
||||
|
||||
void masserEnable();
|
||||
void masserDisable();
|
||||
|
||||
void secundaEnable();
|
||||
void secundaDisable();
|
||||
|
||||
void setThunder(const float factor);
|
||||
|
||||
void setGlare(bool glare);
|
||||
Ogre::Vector3 getRealSunPos();
|
||||
|
||||
private:
|
||||
MWWorld::Environment* mEnvironment;
|
||||
float mHour;
|
||||
int mDay;
|
||||
int mMonth;
|
||||
|
||||
BillboardObject* mSun;
|
||||
BillboardObject* mSunGlare;
|
||||
Moon* mMasser;
|
||||
Moon* mSecunda;
|
||||
|
||||
Ogre::Viewport* mViewport;
|
||||
Ogre::SceneNode* mRootNode;
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
|
||||
Ogre::SceneNode* mAtmosphereDay;
|
||||
Ogre::SceneNode* mAtmosphereNight;
|
||||
|
||||
Ogre::MaterialPtr mCloudMaterial;
|
||||
Ogre::MaterialPtr mAtmosphereMaterial;
|
||||
|
||||
Ogre::MaterialPtr mStarsMaterials[7];
|
||||
|
||||
Ogre::HighLevelGpuProgramPtr mCloudFragmentShader;
|
||||
|
||||
// remember some settings so we don't have to apply them again if they didnt change
|
||||
Ogre::String mClouds;
|
||||
Ogre::String mNextClouds;
|
||||
float mCloudBlendFactor;
|
||||
float mCloudOpacity;
|
||||
float mCloudSpeed;
|
||||
float mStarsOpacity;
|
||||
Ogre::ColourValue mCloudColour;
|
||||
Ogre::ColourValue mSkyColour;
|
||||
|
||||
Ogre::Overlay* mThunderOverlay;
|
||||
Ogre::TextureUnitState* mThunderTextureUnit;
|
||||
|
||||
float mRemainingTransitionTime;
|
||||
|
||||
float mGlareFade;
|
||||
|
||||
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
|
||||
|
||||
bool mEnabled;
|
||||
bool mGlareEnabled;
|
||||
bool mSunEnabled;
|
||||
bool mMasserEnabled;
|
||||
bool mSecundaEnabled;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,13 +25,13 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Float x = runtime[0].mInteger;
|
||||
Interpreter::Type_Float x = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float y = runtime[0].mInteger;
|
||||
Interpreter::Type_Float y = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float z = runtime[0].mInteger;
|
||||
Interpreter::Type_Float z = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
// discard additional arguments (reset), because we have no idea what they mean.
|
||||
|
@ -53,16 +53,16 @@ namespace MWScript
|
|||
std::string actor = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float duration = runtime[0].mInteger;
|
||||
Interpreter::Type_Float duration = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float x = runtime[0].mInteger;
|
||||
Interpreter::Type_Float x = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float y = runtime[0].mInteger;
|
||||
Interpreter::Type_Float y = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float z = runtime[0].mInteger;
|
||||
Interpreter::Type_Float z = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
// discard additional arguments (reset), because we have no idea what they mean.
|
||||
|
@ -99,9 +99,9 @@ namespace MWScript
|
|||
|
||||
void registerExtensions (Compiler::Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("aitravel", "lll/l", opcodeAiTravel,
|
||||
extensions.registerInstruction ("aitravel", "fff/l", opcodeAiTravel,
|
||||
opcodeAiTravelExplicit);
|
||||
extensions.registerInstruction ("aiescort", "cllll/l", opcodeAiEscort,
|
||||
extensions.registerInstruction ("aiescort", "cffff/l", opcodeAiEscort,
|
||||
opcodeAiEscortExplicit);
|
||||
|
||||
extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone,
|
||||
|
|
127
apps/openmw/mwscript/animationextensions.cpp
Normal file
127
apps/openmw/mwscript/animationextensions.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
|
||||
#include "animationextensions.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
|
||||
#include <components/interpreter/interpreter.hpp>
|
||||
#include <components/interpreter/runtime.hpp>
|
||||
#include <components/interpreter/opcodes.hpp>
|
||||
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
#include "interpretercontext.hpp"
|
||||
#include "ref.hpp"
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
namespace Animation
|
||||
{
|
||||
template<class R>
|
||||
class OpSkipAnim : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
context.getWorld().skipAnimation (ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpPlayAnim : public Interpreter::Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string group = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Integer mode = 0;
|
||||
|
||||
if (arg0==1)
|
||||
{
|
||||
mode = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (mode<0 || mode>2)
|
||||
throw std::runtime_error ("animation mode out of range");
|
||||
}
|
||||
|
||||
context.getWorld().playAnimationGroup (ptr, group, mode, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpLoopAnim : public Interpreter::Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string group = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Integer loops = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (loops<0)
|
||||
throw std::runtime_error ("number of animation loops must be non-negative");
|
||||
|
||||
Interpreter::Type_Integer mode = 0;
|
||||
|
||||
if (arg0==1)
|
||||
{
|
||||
mode = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (mode<0 || mode>2)
|
||||
throw std::runtime_error ("animation mode out of range");
|
||||
}
|
||||
|
||||
context.getWorld().playAnimationGroup (ptr, group, mode, loops);
|
||||
}
|
||||
};
|
||||
|
||||
const int opcodeSkipAnim = 0x2000138;
|
||||
const int opcodeSkipAnimExplicit = 0x2000139;
|
||||
const int opcodePlayAnim = 0x20006;
|
||||
const int opcodePlayAnimExplicit = 0x20007;
|
||||
const int opcodeLoopAnim = 0x20008;
|
||||
const int opcodeLoopAnimExplicit = 0x20009;
|
||||
|
||||
void registerExtensions (Compiler::Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("skipanim", "", opcodeSkipAnim, opcodeSkipAnimExplicit);
|
||||
extensions.registerInstruction ("playgroup", "c/l", opcodePlayAnim, opcodePlayAnimExplicit);
|
||||
extensions.registerInstruction ("loopgroup", "cl/l", opcodeLoopAnim, opcodeLoopAnimExplicit);
|
||||
}
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5 (opcodeSkipAnim, new OpSkipAnim<ImplicitRef>);
|
||||
interpreter.installSegment5 (opcodeSkipAnimExplicit, new OpSkipAnim<ExplicitRef>);
|
||||
interpreter.installSegment3 (opcodePlayAnim, new OpPlayAnim<ImplicitRef>);
|
||||
interpreter.installSegment3 (opcodePlayAnimExplicit, new OpPlayAnim<ExplicitRef>);
|
||||
interpreter.installSegment3 (opcodeLoopAnim, new OpLoopAnim<ImplicitRef>);
|
||||
interpreter.installSegment3 (opcodeLoopAnimExplicit, new OpLoopAnim<ExplicitRef>);
|
||||
}
|
||||
}
|
||||
}
|
24
apps/openmw/mwscript/animationextensions.hpp
Normal file
24
apps/openmw/mwscript/animationextensions.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef GAME_SCRIPT_ANIMATIONEXTENSIONS_H
|
||||
#define GAME_SCRIPT_ANIMATIONEXTENSIONS_H
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Extensions;
|
||||
}
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Interpreter;
|
||||
}
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
namespace Animation
|
||||
{
|
||||
void registerExtensions (Compiler::Extensions& extensions);
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "../mwworld/manualref.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/containerutil.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
#include "interpretercontext.hpp"
|
||||
#include "ref.hpp"
|
||||
|
@ -45,8 +45,7 @@ namespace MWScript
|
|||
|
||||
ref.getPtr().getRefData().setCount (count);
|
||||
|
||||
MWWorld::Class::get (ref.getPtr()).insertIntoContainer (ref.getPtr(),
|
||||
MWWorld::Class::get (ptr).getContainerStore (ptr));
|
||||
MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -59,25 +58,16 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
MWScript::InterpreterContext& context
|
||||
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
std::vector<MWWorld::Ptr> list;
|
||||
|
||||
MWWorld::listItemsInContainer (item,
|
||||
MWWorld::Class::get (ptr).getContainerStore (ptr),
|
||||
context.getWorld().getStore(), list);
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
||||
|
||||
Interpreter::Type_Integer sum = 0;
|
||||
|
||||
for (std::vector<MWWorld::Ptr>::iterator iter (list.begin()); iter!=list.end();
|
||||
++iter)
|
||||
{
|
||||
sum += iter->getRefData().getCount();
|
||||
}
|
||||
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
|
||||
if (iter->getCellRef().refID==item)
|
||||
sum += iter->getRefData().getCount();
|
||||
|
||||
runtime.push (sum);
|
||||
}
|
||||
|
@ -92,9 +82,6 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
MWScript::InterpreterContext& context
|
||||
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
|
@ -104,25 +91,23 @@ namespace MWScript
|
|||
if (count<0)
|
||||
throw std::runtime_error ("second argument for RemoveItem must be non-negative");
|
||||
|
||||
std::vector<MWWorld::Ptr> list;
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
||||
|
||||
MWWorld::listItemsInContainer (item,
|
||||
MWWorld::Class::get (ptr).getContainerStore (ptr),
|
||||
context.getWorld().getStore(), list);
|
||||
|
||||
for (std::vector<MWWorld::Ptr>::iterator iter (list.begin());
|
||||
iter!=list.end() && count;
|
||||
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count;
|
||||
++iter)
|
||||
{
|
||||
if (iter->getRefData().getCount()<=count)
|
||||
if (iter->getCellRef().refID==item)
|
||||
{
|
||||
count -= iter->getRefData().getCount();
|
||||
iter->getRefData().setCount (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->getRefData().setCount (iter->getRefData().getCount()-count);
|
||||
count = 0;
|
||||
if (iter->getRefData().getCount()<=count)
|
||||
{
|
||||
count -= iter->getRefData().getCount();
|
||||
iter->getRefData().setCount (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->getRefData().setCount (iter->getRefData().getCount()-count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#include "statsextensions.hpp"
|
||||
#include "controlextensions.hpp"
|
||||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace MWScript
|
|||
|
||||
bool enabled = context.getWorld().toggleCollisionMode();
|
||||
|
||||
context.report (enabled ? "Collsion -> On" : "Collision -> Off");
|
||||
context.report (enabled ? "Collision -> On" : "Collision -> Off");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,11 @@ op 0x20002: AiEscort
|
|||
op 0x20003: AiEscort, explicit reference
|
||||
op 0x20004: Lock
|
||||
op 0x20005: Lock, explicit reference
|
||||
opcodes 0x20006-0x3ffff unused
|
||||
op 0x20006: PlayAnim
|
||||
op 0x20007: PlayAnim, explicit reference
|
||||
op 0x20008: LoopAnim
|
||||
op 0x20009: LoopAnim, explicit reference
|
||||
opcodes 0x2000a-0x3ffff unused
|
||||
|
||||
Segment 4:
|
||||
(not implemented yet)
|
||||
|
@ -109,4 +113,12 @@ op 0x2000134: SetJournalIndex
|
|||
op 0x2000135: GetJournalIndex
|
||||
op 0x2000136: GetPCCell
|
||||
op 0x2000137: GetButtonPressed
|
||||
opcodes 0x2000138-0x3ffffff unused
|
||||
op 0x2000138: SkipAnim
|
||||
op 0x2000139: SkipAnim, expplicit reference
|
||||
op 0x200013b: twf
|
||||
op 0x200013c: FadeIn
|
||||
op 0x200013d: FadeOut
|
||||
op 0x200013e: FadeTo
|
||||
op 0x200013f: GetCurrentWeather
|
||||
op 0x2000140: ChangeWeather
|
||||
opcodes 0x2000141-0x3ffffff unused
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "aiextensions.hpp"
|
||||
#include "controlextensions.hpp"
|
||||
#include "dialogueextensions.hpp"
|
||||
#include "animationextensions.hpp"
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
|
@ -29,6 +30,7 @@ namespace MWScript
|
|||
Ai::registerExtensions (extensions);
|
||||
Control::registerExtensions (extensions);
|
||||
Dialogue::registerExtensions (extensions);
|
||||
Animation::registerExtensions (extensions);
|
||||
}
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
|
@ -44,5 +46,6 @@ namespace MWScript
|
|||
Ai::installOpcodes (interpreter);
|
||||
Control::installOpcodes (interpreter);
|
||||
Dialogue::installOpcodes (interpreter);
|
||||
Animation::installOpcodes (interpreter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,75 @@ namespace MWScript
|
|||
context.getWorld().toggleRenderMode (MWWorld::World::Render_CollisionDebug);
|
||||
|
||||
context.report (enabled ?
|
||||
"Collsion Mesh Rendering -> On" : "Collision Mesh Rendering -> Off");
|
||||
"Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off");
|
||||
}
|
||||
};
|
||||
|
||||
class OpToggleWireframe : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
bool enabled =
|
||||
context.getWorld().toggleRenderMode (MWWorld::World::Render_Wireframe);
|
||||
|
||||
context.report (enabled ?
|
||||
"Wireframe Rendering -> On" : "Wireframe Rendering -> Off");
|
||||
}
|
||||
};
|
||||
|
||||
class OpFadeIn : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
Interpreter::Type_Float time = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
context.getWorld().getFader()->fadeIn(time);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFadeOut : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
Interpreter::Type_Float time = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
context.getWorld().getFader()->fadeOut(time);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFadeTo : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
Interpreter::Type_Float alpha = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Float time = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
context.getWorld().getFader()->fadeTo(alpha, time);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -115,6 +183,10 @@ namespace MWScript
|
|||
const int opcodeUnlock = 0x200008c;
|
||||
const int opcodeUnlockExplicit = 0x200008d;
|
||||
const int opcodeToggleCollisionDebug = 0x2000132;
|
||||
const int opcodeToggleWireframe = 0x200013b;
|
||||
const int opcodeFadeIn = 0x200013c;
|
||||
const int opcodeFadeOut = 0x200013d;
|
||||
const int opcodeFadeTo = 0x200013e;
|
||||
|
||||
void registerExtensions (Compiler::Extensions& extensions)
|
||||
{
|
||||
|
@ -127,6 +199,11 @@ namespace MWScript
|
|||
extensions.registerInstruction ("togglecollisiongrid", "", opcodeToggleCollisionDebug);
|
||||
extensions.registerInstruction ("tcb", "", opcodeToggleCollisionDebug);
|
||||
extensions.registerInstruction ("tcg", "", opcodeToggleCollisionDebug);
|
||||
extensions.registerInstruction ("twf", "", opcodeToggleWireframe);
|
||||
extensions.registerInstruction ("togglewireframe", "", opcodeToggleWireframe);
|
||||
extensions.registerInstruction ("fadein", "f", opcodeFadeIn);
|
||||
extensions.registerInstruction ("fadeout", "f", opcodeFadeOut);
|
||||
extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo);
|
||||
}
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
|
@ -139,6 +216,10 @@ namespace MWScript
|
|||
interpreter.installSegment5 (opcodeUnlock, new OpUnlock<ImplicitRef>);
|
||||
interpreter.installSegment5 (opcodeUnlockExplicit, new OpUnlock<ExplicitRef>);
|
||||
interpreter.installSegment5 (opcodeToggleCollisionDebug, new OpToggleCollisionDebug);
|
||||
interpreter.installSegment5 (opcodeToggleWireframe, new OpToggleWireframe);
|
||||
interpreter.installSegment5 (opcodeFadeIn, new OpFadeIn);
|
||||
interpreter.installSegment5 (opcodeFadeOut, new OpFadeOut);
|
||||
interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,12 +79,46 @@ namespace MWScript
|
|||
runtime.push (context.getWorld().getSecundaPhase());
|
||||
}
|
||||
};
|
||||
|
||||
class OpGetCurrentWeather : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
runtime.push (context.getWorld().getCurrentWeather());
|
||||
}
|
||||
};
|
||||
|
||||
class OpChangeWeather : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string region = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Integer id = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
context.getWorld().changeWeather(region, id);
|
||||
}
|
||||
};
|
||||
|
||||
const int opcodeToggleSky = 0x2000021;
|
||||
const int opcodeTurnMoonWhite = 0x2000022;
|
||||
const int opcodeTurnMoonRed = 0x2000023;
|
||||
const int opcodeGetMasserPhase = 0x2000024;
|
||||
const int opcodeGetSecundaPhase = 0x2000025;
|
||||
const int opcodeGetCurrentWeather = 0x200013f;
|
||||
const int opcodeChangeWeather = 0x2000140;
|
||||
|
||||
void registerExtensions (Compiler::Extensions& extensions)
|
||||
{
|
||||
|
@ -92,8 +126,10 @@ namespace MWScript
|
|||
extensions.registerInstruction ("ts", "", opcodeToggleSky);
|
||||
extensions.registerInstruction ("turnmoonwhite", "", opcodeTurnMoonWhite);
|
||||
extensions.registerInstruction ("turnmoonred", "", opcodeTurnMoonRed);
|
||||
extensions.registerInstruction ("changeweather", "Sl", opcodeChangeWeather);
|
||||
extensions.registerFunction ("getmasserphase", 'l', "", opcodeGetMasserPhase);
|
||||
extensions.registerFunction ("getsecundaphase", 'l', "", opcodeGetSecundaPhase);
|
||||
extensions.registerFunction ("getcurrentweather", 'l', "", opcodeGetCurrentWeather);
|
||||
}
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
|
@ -103,6 +139,8 @@ namespace MWScript
|
|||
interpreter.installSegment5 (opcodeTurnMoonRed, new OpTurnMoonRed);
|
||||
interpreter.installSegment5 (opcodeGetMasserPhase, new OpGetMasserPhase);
|
||||
interpreter.installSegment5 (opcodeGetSecundaPhase, new OpGetSecundaPhase);
|
||||
interpreter.installSegment5 (opcodeGetCurrentWeather, new OpGetCurrentWeather);
|
||||
interpreter.installSegment5 (opcodeChangeWeather, new OpChangeWeather);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "interpretercontext.hpp"
|
||||
#include "ref.hpp"
|
||||
|
|
|
@ -4,15 +4,12 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include <openengine/sound/sndmanager.hpp>
|
||||
#include <mangle/sound/clients/ogre_listener_mover.hpp>
|
||||
#include <mangle/sound/clients/ogre_output_updater.hpp>
|
||||
|
||||
#include <components/file_finder/file_finder.hpp>
|
||||
#include <components/esm_store/store.hpp>
|
||||
|
||||
#include "../mwworld/environment.hpp"
|
||||
|
@ -46,7 +43,6 @@ using namespace std;
|
|||
|
||||
using namespace Mangle::Sound;
|
||||
typedef OEngine::Sound::SoundManager OEManager;
|
||||
typedef OEngine::Sound::SoundManagerPtr OEManagerPtr;
|
||||
|
||||
// Set the position on a sound based on a Ptr.
|
||||
static void setPos(SoundPtr &snd, const MWWorld::Ptr ref)
|
||||
|
@ -61,158 +57,69 @@ static void setPos(SoundPtr &snd, const MWWorld::Ptr ref)
|
|||
|
||||
namespace MWSound
|
||||
{
|
||||
struct SoundManager::SoundImpl
|
||||
{
|
||||
/* This is the sound manager. It loades, stores and deletes
|
||||
sounds based on the sound factory it is given.
|
||||
*/
|
||||
OEManagerPtr mgr;
|
||||
SoundPtr music;
|
||||
|
||||
/* This class calls update() on the sound manager each frame
|
||||
using and Ogre::FrameListener
|
||||
*/
|
||||
Mangle::Sound::OgreOutputUpdater updater;
|
||||
|
||||
/* This class tracks the movement of an Ogre::Camera and moves
|
||||
a sound listener automatically to follow it.
|
||||
*/
|
||||
Mangle::Sound::OgreListenerMover cameraTracker;
|
||||
|
||||
const ESMS::ESMStore &store;
|
||||
|
||||
typedef std::map<std::string,Mangle::Sound::WSoundPtr> IDMap;
|
||||
typedef std::map<MWWorld::Ptr,IDMap> PtrMap;
|
||||
PtrMap sounds;
|
||||
|
||||
// This is used for case insensitive and slash-type agnostic file
|
||||
// finding. It takes DOS paths (any case, \\ slashes or / slashes)
|
||||
// relative to the sound dir, and translates them into full paths
|
||||
// of existing files in the filesystem, if they exist.
|
||||
bool FSstrict;
|
||||
FileFinder::FileFinder files;
|
||||
FileFinder::FileFinderStrict strict;
|
||||
FileFinder::FileFinder musicpath;
|
||||
FileFinder::FileFinderStrict musicpathStrict;
|
||||
|
||||
SoundImpl(Ogre::Root *root, Ogre::Camera *camera,
|
||||
const ESMS::ESMStore &str,
|
||||
const std::string &soundDir, const std::string &musicDir, bool fsstrict)
|
||||
: mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
|
||||
, updater(mgr)
|
||||
, cameraTracker(mgr)
|
||||
, store(str)
|
||||
, files(soundDir), strict(soundDir)
|
||||
,musicpath(musicDir), musicpathStrict(musicDir)
|
||||
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
|
||||
const Files::PathContainer& dataDirs,
|
||||
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
||||
: mFSStrict(fsstrict)
|
||||
, mEnvironment(environment)
|
||||
, mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
|
||||
, updater(mgr)
|
||||
, cameraTracker(mgr)
|
||||
, mCurrentPlaylist(NULL)
|
||||
, mUsingSound(useSound)
|
||||
{
|
||||
FSstrict = fsstrict;
|
||||
cout << "Sound output: " << SOUND_OUT << endl;
|
||||
cout << "Sound decoder: " << SOUND_IN << endl;
|
||||
// Attach the camera to the camera tracker
|
||||
cameraTracker.followCamera(camera);
|
||||
|
||||
// Tell Ogre to update the sound system each frame
|
||||
root->addFrameListener(&updater);
|
||||
}
|
||||
|
||||
~SoundImpl()
|
||||
{
|
||||
Ogre::Root::getSingleton().removeFrameListener(&updater);
|
||||
cameraTracker.unfollowCamera();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static std::string toMp3(std::string str)
|
||||
{
|
||||
std::string::size_type i = str.rfind('.');
|
||||
if(str.find('/', i) == std::string::npos &&
|
||||
str.find('\\', i) == std::string::npos)
|
||||
str = str.substr(0, i) + ".mp3";
|
||||
else
|
||||
str += ".mp3";
|
||||
return str;
|
||||
}
|
||||
|
||||
bool hasFile(const std::string &str, bool music = false)
|
||||
{
|
||||
if(FSstrict == false)
|
||||
if(useSound)
|
||||
{
|
||||
if(music)
|
||||
{
|
||||
if(musicpath.has(str)) return true;
|
||||
// The music library will accept these filetypes
|
||||
// If none is given then it will accept all filetypes
|
||||
std::vector<std::string> acceptableExtensions;
|
||||
acceptableExtensions.push_back(".mp3");
|
||||
acceptableExtensions.push_back(".wav");
|
||||
acceptableExtensions.push_back(".ogg");
|
||||
acceptableExtensions.push_back(".flac");
|
||||
|
||||
// Not found? Try with .mp3
|
||||
return musicpath.has(toMp3(str));
|
||||
}
|
||||
else
|
||||
// Makes a list of all sound files, searches in reverse for priority reasons
|
||||
for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it)
|
||||
{
|
||||
if(files.has(str)) return true;
|
||||
return files.has(toMp3(str));
|
||||
Files::FileLister(*it / std::string("Sound"), mSoundFiles, true);
|
||||
}
|
||||
|
||||
// Makes a FileLibrary of all music files, searches in reverse for priority reasons
|
||||
for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it)
|
||||
{
|
||||
mMusicLibrary.add(*it / std::string("Music"), true, mFSStrict, acceptableExtensions);
|
||||
}
|
||||
|
||||
std::string anything = "anything"; // anything is better that a segfault
|
||||
mCurrentPlaylist = mMusicLibrary.section(anything, mFSStrict); // now points to an empty path
|
||||
|
||||
std::cout << "Sound output: " << SOUND_OUT << std::endl;
|
||||
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
|
||||
// Attach the camera to the camera tracker
|
||||
cameraTracker.followCamera(camera);
|
||||
|
||||
// Tell Ogre to update the sound system each frame
|
||||
root->addFrameListener(&updater);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(music)
|
||||
{
|
||||
if(musicpathStrict.has(str)) return true;
|
||||
}
|
||||
|
||||
// Not found? Try with .mp3
|
||||
return musicpathStrict.has(toMp3(str));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strict.has(str)) return true;
|
||||
return strict.has(toMp3(str));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a Morrowind sound path (eg. Fx\funny.wav) to full path
|
||||
// with proper slash conversion (eg. datadir/Sound/Fx/funny.wav)
|
||||
std::string convertPath(const std::string &str, bool music = false)
|
||||
SoundManager::~SoundManager()
|
||||
{
|
||||
if(FSstrict == false)
|
||||
if(mUsingSound)
|
||||
{
|
||||
// Search and return
|
||||
if(music && musicpath.has(str))
|
||||
return musicpath.lookup(str);
|
||||
else if(files.has(str))
|
||||
return files.lookup(str);
|
||||
|
||||
// Try mp3 if the wav wasn't found
|
||||
std::string mp3 = toMp3(str);
|
||||
if(music && musicpath.has(mp3))
|
||||
return musicpath.lookup(mp3);
|
||||
else if(files.has(mp3))
|
||||
return files.lookup(mp3);
|
||||
Ogre::Root::getSingleton().removeFrameListener(&updater);
|
||||
cameraTracker.unfollowCamera();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(music && musicpathStrict.has(str))
|
||||
return musicpathStrict.lookup(str);
|
||||
else if(strict.has(str))
|
||||
return strict.lookup(str);
|
||||
|
||||
// Try mp3 if the wav wasn't found
|
||||
std::string mp3 = toMp3(str);
|
||||
if(music && musicpathStrict.has(mp3))
|
||||
return musicpathStrict.lookup(mp3);
|
||||
else if(strict.has(str))
|
||||
return strict.lookup(mp3);
|
||||
}
|
||||
|
||||
// Give up
|
||||
return "";
|
||||
}
|
||||
|
||||
// Convert a soundId to file name, and modify the volume
|
||||
// according to the sounds local volume setting, minRange and
|
||||
// maxRange.
|
||||
std::string lookup(const std::string &soundId,
|
||||
std::string SoundManager::lookup(const std::string &soundId,
|
||||
float &volume, float &min, float &max)
|
||||
{
|
||||
const ESM::Sound *snd = store.sounds.search(soundId);
|
||||
const ESM::Sound *snd = mEnvironment.mWorld->getStore().sounds.search(soundId);
|
||||
if(snd == NULL) return "";
|
||||
|
||||
if(snd->data.volume == 0)
|
||||
|
@ -233,16 +140,16 @@ namespace MWSound
|
|||
max = std::max(min, max);
|
||||
}
|
||||
|
||||
return convertPath(snd->sound);
|
||||
return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict, false);
|
||||
}
|
||||
|
||||
// Add a sound to the list and play it
|
||||
void add(const std::string &file,
|
||||
void SoundManager::add(const std::string &file,
|
||||
MWWorld::Ptr ptr,
|
||||
const std::string &id,
|
||||
float volume, float pitch,
|
||||
float min, float max,
|
||||
bool loop)
|
||||
bool loop, bool untracked)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -254,17 +161,20 @@ namespace MWSound
|
|||
setPos(snd, ptr);
|
||||
snd->play();
|
||||
|
||||
sounds[ptr][id] = WSoundPtr(snd);
|
||||
if (!untracked)
|
||||
{
|
||||
sounds[ptr][id] = WSoundPtr(snd);
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cout << "Error loading " << file << ", skipping.\n";
|
||||
std::cout << "Error loading " << file << ", skipping.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Clears all the sub-elements of a given iterator, and then
|
||||
// removes it from 'sounds'.
|
||||
void clearAll(PtrMap::iterator it)
|
||||
void SoundManager::clearAll(PtrMap::iterator& it)
|
||||
{
|
||||
IDMap::iterator sit = it->second.begin();
|
||||
|
||||
|
@ -285,7 +195,7 @@ namespace MWSound
|
|||
|
||||
// Stop a sound and remove it from the list. If id="" then
|
||||
// remove the entire object and stop all its sounds.
|
||||
void remove(MWWorld::Ptr ptr, const std::string &id = "")
|
||||
void SoundManager::remove(MWWorld::Ptr ptr, const std::string &id)
|
||||
{
|
||||
PtrMap::iterator it = sounds.find(ptr);
|
||||
if(it != sounds.end())
|
||||
|
@ -308,7 +218,7 @@ namespace MWSound
|
|||
}
|
||||
}
|
||||
|
||||
bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const
|
||||
bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const
|
||||
{
|
||||
PtrMap::const_iterator it = sounds.find(ptr);
|
||||
if(it != sounds.end())
|
||||
|
@ -332,7 +242,7 @@ namespace MWSound
|
|||
}
|
||||
|
||||
// Remove all references to objects belonging to a given cell
|
||||
void removeCell(const MWWorld::Ptr::CellStore *cell)
|
||||
void SoundManager::removeCell(const MWWorld::Ptr::CellStore *cell)
|
||||
{
|
||||
PtrMap::iterator it2, it = sounds.begin();
|
||||
while(it != sounds.end())
|
||||
|
@ -344,7 +254,7 @@ namespace MWSound
|
|||
}
|
||||
}
|
||||
|
||||
void updatePositions(MWWorld::Ptr ptr)
|
||||
void SoundManager::updatePositions(MWWorld::Ptr ptr)
|
||||
{
|
||||
// Find the reference (if any)
|
||||
PtrMap::iterator it = sounds.find(ptr);
|
||||
|
@ -362,213 +272,234 @@ namespace MWSound
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void SoundManager::streamMusicFull (const std::string& filename)
|
||||
void SoundManager::stopMusic()
|
||||
{
|
||||
if (music)
|
||||
music->stop();
|
||||
setPlaylist();
|
||||
}
|
||||
|
||||
|
||||
void SoundManager::streamMusicFull(const std::string& filename)
|
||||
{
|
||||
if(!mData) return;
|
||||
|
||||
// Play the sound and tell it to stream, if possible. TODO:
|
||||
// Store the reference, the jukebox will need to check status,
|
||||
// control volume etc.
|
||||
if (mData->music)
|
||||
mData->music->stop();
|
||||
mData->music = mData->mgr->load(filename);
|
||||
mData->music->setStreaming(true);
|
||||
mData->music->setVolume(0.4);
|
||||
mData->music->play();
|
||||
if (music)
|
||||
music->stop();
|
||||
music = mgr->load(filename);
|
||||
music->setStreaming(true);
|
||||
music->setVolume(0.4);
|
||||
music->play();
|
||||
|
||||
}
|
||||
|
||||
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
|
||||
const ESMS::ESMStore &store,
|
||||
boost::filesystem::path dataDir,
|
||||
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
||||
: mData(NULL), fsStrict (fsstrict), mEnvironment (environment)
|
||||
{
|
||||
MP3Lookup(dataDir / "Music/Explore/");
|
||||
if(useSound)
|
||||
mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict);
|
||||
|
||||
|
||||
test.name = "";
|
||||
total = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager()
|
||||
{
|
||||
if(mData)
|
||||
delete mData;
|
||||
}
|
||||
|
||||
void SoundManager::streamMusic(const std::string& filename)
|
||||
{
|
||||
if(mData->hasFile(filename, true))
|
||||
std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string();
|
||||
if(!filePath.empty())
|
||||
{
|
||||
std::string fullpath = mData->convertPath(filename, true);
|
||||
streamMusicFull(fullpath);
|
||||
streamMusicFull(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SoundManager::MP3Lookup(boost::filesystem::path dir)
|
||||
{
|
||||
boost::filesystem::directory_iterator dir_iter(dir), dir_end;
|
||||
|
||||
std::string mp3extension = ".mp3";
|
||||
for(;dir_iter != dir_end; dir_iter++)
|
||||
{
|
||||
if(boost::filesystem::extension(*dir_iter) == mp3extension)
|
||||
{
|
||||
files.push_back(*dir_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::startRandomTitle()
|
||||
{
|
||||
std::vector<boost::filesystem::path>::iterator fileIter;
|
||||
|
||||
if(files.size() > 0)
|
||||
{
|
||||
if(mCurrentPlaylist && !mCurrentPlaylist->empty())
|
||||
{
|
||||
fileIter = files.begin();
|
||||
srand ( time(NULL) );
|
||||
int r = rand() % files.size() + 1; //old random code
|
||||
Files::PathContainer::const_iterator fileIter = mCurrentPlaylist->begin();
|
||||
srand( time(NULL) );
|
||||
int r = rand() % mCurrentPlaylist->size() + 1; //old random code
|
||||
|
||||
for(int i = 1; i < r; i++)
|
||||
{
|
||||
fileIter++;
|
||||
}
|
||||
std::advance(fileIter, r - 1);
|
||||
std::string music = fileIter->string();
|
||||
std::cout << "Playing " << music << "\n";
|
||||
|
||||
try
|
||||
{
|
||||
std::cout << "Playing " << music << "\n";
|
||||
streamMusicFull(music);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
catch (std::exception &e)
|
||||
{
|
||||
std::cout << " Music Error: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SoundManager::isMusicPlaying()
|
||||
{
|
||||
bool test = false;
|
||||
if(mData && mData->music)
|
||||
if(music)
|
||||
{
|
||||
test = mData->music->isPlaying();
|
||||
test = music->isPlaying();
|
||||
}
|
||||
return test;
|
||||
}
|
||||
|
||||
SoundManager::SoundImpl SoundManager::getMData()
|
||||
{
|
||||
// bool test = mData->music->isPlaying();
|
||||
return *mData;
|
||||
}
|
||||
bool SoundManager::setPlaylist(std::string playlist)
|
||||
{
|
||||
const Files::PathContainer* previousPlaylist;
|
||||
previousPlaylist = mCurrentPlaylist;
|
||||
if (playlist == "")
|
||||
{
|
||||
mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict);
|
||||
}
|
||||
else if(mMusicLibrary.containsSection(playlist, mFSStrict))
|
||||
{
|
||||
mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Warning: playlist named " << playlist << " does not exist.\n";
|
||||
}
|
||||
return previousPlaylist == mCurrentPlaylist;
|
||||
}
|
||||
|
||||
void SoundManager::playPlaylist(std::string playlist)
|
||||
{
|
||||
if (!mUsingSound)
|
||||
return;
|
||||
|
||||
if (playlist == "")
|
||||
{
|
||||
if(!isMusicPlaying())
|
||||
{
|
||||
startRandomTitle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!setPlaylist(playlist))
|
||||
{
|
||||
startRandomTitle();
|
||||
}
|
||||
else if (!isMusicPlaying())
|
||||
{
|
||||
startRandomTitle();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
|
||||
{
|
||||
if (!mUsingSound)
|
||||
return;
|
||||
|
||||
// The range values are not tested
|
||||
if(!mData) return;
|
||||
if(mData->hasFile(filename))
|
||||
mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false);
|
||||
std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true);
|
||||
if(!filePath.empty())
|
||||
add(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false);
|
||||
else
|
||||
cout << "Sound file " << filename << " not found, skipping.\n";
|
||||
std::cout << "Sound file " << filename << " not found, skipping.\n";
|
||||
}
|
||||
|
||||
bool SoundManager::sayDone (MWWorld::Ptr ptr) const
|
||||
{
|
||||
if(!mData) return false;
|
||||
return !mData->isPlaying(ptr, "_say_sound");
|
||||
return !isPlaying(ptr, "_say_sound");
|
||||
}
|
||||
|
||||
|
||||
void SoundManager::playSound (const std::string& soundId, float volume, float pitch)
|
||||
void SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop)
|
||||
{
|
||||
if(!mData) return;
|
||||
// Play and forget
|
||||
float min, max;
|
||||
const std::string &file = mData->lookup(soundId, volume, min, max);
|
||||
if(file != "")
|
||||
{
|
||||
SoundPtr snd = mData->mgr->load(file);
|
||||
const std::string &file = lookup(soundId, volume, min, max);
|
||||
if (file != "")
|
||||
{
|
||||
SoundPtr snd = mgr->load(file);
|
||||
snd->setRepeat(loop);
|
||||
snd->setVolume(volume);
|
||||
snd->setRange(min,max);
|
||||
snd->setPitch(pitch);
|
||||
snd->setRelative(true);
|
||||
snd->play();
|
||||
}
|
||||
|
||||
if (loop)
|
||||
{
|
||||
// Only add the looping sound once
|
||||
IDMap::iterator it = mLoopedSounds.find(soundId);
|
||||
if(it == mLoopedSounds.end())
|
||||
{
|
||||
mLoopedSounds[soundId] = WSoundPtr(snd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId,
|
||||
float volume, float pitch, bool loop)
|
||||
float volume, float pitch, bool loop, bool untracked)
|
||||
{
|
||||
if(!mData) return;
|
||||
|
||||
// Look up the sound in the ESM data
|
||||
float min, max;
|
||||
const std::string &file = mData->lookup(soundId, volume, min, max);
|
||||
if(file != "")
|
||||
mData->add(file, ptr, soundId, volume, pitch, min, max, loop);
|
||||
const std::string &file = lookup(soundId, volume, min, max);
|
||||
if (file != "")
|
||||
add(file, ptr, soundId, volume, pitch, min, max, loop, untracked);
|
||||
}
|
||||
|
||||
void SoundManager::stopSound3D (MWWorld::Ptr ptr, const std::string& soundId)
|
||||
{
|
||||
if(!mData) return;
|
||||
mData->remove(ptr, soundId);
|
||||
remove(ptr, soundId);
|
||||
}
|
||||
|
||||
void SoundManager::stopSound (MWWorld::Ptr::CellStore *cell)
|
||||
{
|
||||
if(!mData) return;
|
||||
mData->removeCell(cell);
|
||||
removeCell(cell);
|
||||
}
|
||||
|
||||
void SoundManager::stopSound(const std::string& soundId)
|
||||
{
|
||||
IDMap::iterator it = mLoopedSounds.find(soundId);
|
||||
if(it != mLoopedSounds.end())
|
||||
{
|
||||
SoundPtr snd = it->second.lock();
|
||||
if(snd) snd->stop();
|
||||
mLoopedSounds.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const
|
||||
{
|
||||
// Mark all sounds as playing, otherwise the scripts will just
|
||||
// keep trying to play them every frame.
|
||||
if(!mData) return true;
|
||||
|
||||
return mData->isPlaying(ptr, soundId);
|
||||
return isPlaying(ptr, soundId);
|
||||
}
|
||||
|
||||
void SoundManager::updateObject(MWWorld::Ptr ptr)
|
||||
{
|
||||
if(!mData) return;
|
||||
mData->updatePositions(ptr);
|
||||
updatePositions(ptr);
|
||||
}
|
||||
|
||||
void SoundManager::update (float duration)
|
||||
{
|
||||
std::string effect;
|
||||
|
||||
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
|
||||
static int total = 0;
|
||||
static std::string regionName = "";
|
||||
static float timePassed = 0.0;
|
||||
timePassed += duration;
|
||||
|
||||
//If the region has changed
|
||||
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){
|
||||
timer.restart();
|
||||
if (test.name != current->cell->region)
|
||||
if(!(current->cell->data.flags & current->cell->Interior) && timePassed >= 10)
|
||||
{
|
||||
|
||||
ESM::Region test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region));
|
||||
|
||||
timePassed = 0;
|
||||
if (regionName != current->cell->region)
|
||||
{
|
||||
regionName = current->cell->region;
|
||||
total = 0;
|
||||
test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region));
|
||||
}
|
||||
|
||||
if(test.soundList.size() > 0)
|
||||
{
|
||||
std::vector<ESM::Region::SoundRef>::iterator soundIter = test.soundList.begin();
|
||||
//mEnvironment.mSoundManager
|
||||
if(total == 0){
|
||||
while (!(soundIter == test.soundList.end()))
|
||||
if(total == 0)
|
||||
{
|
||||
while (soundIter != test.soundList.end())
|
||||
{
|
||||
ESM::NAME32 go = soundIter->sound;
|
||||
int chance = (int) soundIter->chance;
|
||||
//ESM::NAME32 go = soundIter->sound;
|
||||
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
||||
soundIter++;
|
||||
total += chance;
|
||||
|
@ -578,21 +509,19 @@ namespace MWSound
|
|||
int r = rand() % total; //old random code
|
||||
int pos = 0;
|
||||
soundIter = test.soundList.begin();
|
||||
while (!(soundIter == test.soundList.end()))
|
||||
while (soundIter != test.soundList.end())
|
||||
{
|
||||
const ESM::NAME32 go = soundIter->sound;
|
||||
const std::string go = soundIter->sound.toString();
|
||||
int chance = (int) soundIter->chance;
|
||||
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
||||
soundIter++;
|
||||
if( r - pos < chance)
|
||||
{
|
||||
effect = go.name;
|
||||
//play sound
|
||||
std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
||||
mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0);
|
||||
std::cout << "Sound: " << go <<" Chance:" << chance << "\n";
|
||||
mEnvironment.mSoundManager->playSound(go, 20.0, 1.0);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
pos += chance;
|
||||
}
|
||||
|
@ -600,7 +529,7 @@ namespace MWSound
|
|||
}
|
||||
else if(current->cell->data.flags & current->cell->Interior)
|
||||
{
|
||||
test.name = "";
|
||||
regionName = "";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue