mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 15:09:39 +00:00
Merge remote branch 'corristo/header-refactoring' into header-refactoring
Conflicts: CMakeLists.txt
This commit is contained in:
commit
7c506301b7
88 changed files with 2628 additions and 2157 deletions
104
CMakeLists.txt
104
CMakeLists.txt
|
@ -1,5 +1,9 @@
|
||||||
project(OpenMW)
|
project(OpenMW)
|
||||||
|
|
||||||
|
IF (APPLE)
|
||||||
|
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/OpenMW.app")
|
||||||
|
ENDIF (APPLE)
|
||||||
|
|
||||||
# Sound source selection
|
# Sound source selection
|
||||||
option(USE_AUDIERE "use Audiere for sound" OFF)
|
option(USE_AUDIERE "use Audiere for sound" OFF)
|
||||||
option(USE_FFMPEG "use ffmpeg for sound" OFF)
|
option(USE_FFMPEG "use ffmpeg for sound" OFF)
|
||||||
|
@ -14,7 +18,7 @@ if(DPKG_PROGRAM)
|
||||||
else()
|
else()
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# set path inside bundle
|
# set path inside bundle
|
||||||
set(MORROWIND_DATA_FILES "Contents/Resources/data" CACHE PATH "location of Morrowind data files")
|
set(MORROWIND_DATA_FILES "../data" CACHE PATH "location of Morrowind data files")
|
||||||
set(MORROWIND_RESOURCE_FILES "Contents/Resources/resources" CACHE PATH "location of Morrowind data files")
|
set(MORROWIND_RESOURCE_FILES "Contents/Resources/resources" CACHE PATH "location of Morrowind data files")
|
||||||
else()
|
else()
|
||||||
set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files")
|
set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files")
|
||||||
|
@ -123,10 +127,48 @@ source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER})
|
||||||
|
|
||||||
file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp)
|
file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp)
|
||||||
set(ESM
|
set(ESM
|
||||||
${COMP_DIR}/esm/load_impl.cpp
|
|
||||||
${COMP_DIR}/esm/skill.cpp
|
|
||||||
${COMP_DIR}/esm/attr.cpp
|
${COMP_DIR}/esm/attr.cpp
|
||||||
${COMP_DIR}/esm/class.cpp
|
${COMP_DIR}/esm/esm_reader.cpp
|
||||||
|
${COMP_DIR}/esm/loadland.cpp
|
||||||
|
${COMP_DIR}/esm/loadacti.cpp
|
||||||
|
${COMP_DIR}/esm/loadalch.cpp
|
||||||
|
${COMP_DIR}/esm/loadappa.cpp
|
||||||
|
${COMP_DIR}/esm/loadarmo.cpp
|
||||||
|
${COMP_DIR}/esm/loadbody.cpp
|
||||||
|
${COMP_DIR}/esm/loadbook.cpp
|
||||||
|
${COMP_DIR}/esm/loadbsgn.cpp
|
||||||
|
${COMP_DIR}/esm/loadcell.cpp
|
||||||
|
${COMP_DIR}/esm/loadclas.cpp
|
||||||
|
${COMP_DIR}/esm/loadclot.cpp
|
||||||
|
${COMP_DIR}/esm/loadcont.cpp
|
||||||
|
${COMP_DIR}/esm/loadcrea.cpp
|
||||||
|
${COMP_DIR}/esm/loaddial.cpp
|
||||||
|
${COMP_DIR}/esm/loaddoor.cpp
|
||||||
|
${COMP_DIR}/esm/loadench.cpp
|
||||||
|
${COMP_DIR}/esm/loadfact.cpp
|
||||||
|
${COMP_DIR}/esm/loadglob.cpp
|
||||||
|
${COMP_DIR}/esm/loadgmst.cpp
|
||||||
|
${COMP_DIR}/esm/loadinfo.cpp
|
||||||
|
${COMP_DIR}/esm/loadingr.cpp
|
||||||
|
${COMP_DIR}/esm/loadlevlist.cpp
|
||||||
|
${COMP_DIR}/esm/loadligh.cpp
|
||||||
|
${COMP_DIR}/esm/loadlocks.cpp
|
||||||
|
${COMP_DIR}/esm/loadltex.cpp
|
||||||
|
${COMP_DIR}/esm/loadmgef.cpp
|
||||||
|
${COMP_DIR}/esm/loadmisc.cpp
|
||||||
|
${COMP_DIR}/esm/loadnpc.cpp
|
||||||
|
${COMP_DIR}/esm/loadpgrd.cpp
|
||||||
|
${COMP_DIR}/esm/loadrace.cpp
|
||||||
|
${COMP_DIR}/esm/loadregn.cpp
|
||||||
|
${COMP_DIR}/esm/loadscpt.cpp
|
||||||
|
${COMP_DIR}/esm/loadskil.cpp
|
||||||
|
${COMP_DIR}/esm/loadsndg.cpp
|
||||||
|
${COMP_DIR}/esm/loadsoun.cpp
|
||||||
|
${COMP_DIR}/esm/loadspel.cpp
|
||||||
|
${COMP_DIR}/esm/loadsscr.cpp
|
||||||
|
${COMP_DIR}/esm/loadstat.cpp
|
||||||
|
${COMP_DIR}/esm/loadweap.cpp
|
||||||
|
|
||||||
)
|
)
|
||||||
source_group(components\\esm FILES ${ESM_HEADER} ${ESM})
|
source_group(components\\esm FILES ${ESM_HEADER} ${ESM})
|
||||||
|
|
||||||
|
@ -286,25 +328,50 @@ add_definitions(-DCAELUM_STATIC)
|
||||||
|
|
||||||
# Specify build paths
|
# Specify build paths
|
||||||
|
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
|
if (APPLE)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
|
||||||
|
else (APPLE)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
|
||||||
|
endif (APPLE)
|
||||||
|
|
||||||
# Other files
|
# Other files
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32
|
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32
|
||||||
"${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY)
|
"${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY)
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux
|
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux
|
||||||
"${OpenMW_BINARY_DIR}/plugins.cfg")
|
"${OpenMW_BINARY_DIR}/plugins.cfg")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac
|
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac
|
||||||
"${OpenMW_BINARY_DIR}/plugins.cfg")
|
"${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg")
|
||||||
|
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
|
||||||
|
"${APP_BUNDLE_DIR}/Contents/Info.plist" COPYONLY)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
|
"${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg")
|
||||||
|
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
|
||||||
|
|
||||||
# Compiler settings
|
# Compiler settings
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
if (CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
@ -315,10 +382,15 @@ endif (CMAKE_COMPILER_IS_GNUCC)
|
||||||
# Apple bundling
|
# Apple bundling
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(MISC_FILES
|
set(MISC_FILES
|
||||||
${OpenMW_BINARY_DIR}/openmw.cfg
|
${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg
|
||||||
${OpenMW_BINARY_DIR}/plugins.cfg)
|
${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg)
|
||||||
|
|
||||||
|
set(OGRE_PLUGINS
|
||||||
|
${APP_BUNDLE_DIR}/Contents/Plugins/*)
|
||||||
|
|
||||||
install(FILES ${MISC_FILES} DESTINATION ../MacOS)
|
install(FILES ${MISC_FILES} DESTINATION ../MacOS)
|
||||||
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ../Resources)
|
install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Plugins" DESTINATION ..)
|
||||||
|
install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Resources/resources" DESTINATION ../Resources)
|
||||||
set(CPACK_GENERATOR "Bundle")
|
set(CPACK_GENERATOR "Bundle")
|
||||||
set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist")
|
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_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns")
|
||||||
|
|
|
@ -49,8 +49,8 @@ Getting OpenMW Working
|
||||||
--link-shared,static --prefix=$OMW_LIB_PREFIX install
|
--link-shared,static --prefix=$OMW_LIB_PREFIX install
|
||||||
|
|
||||||
|
|
||||||
5. Download [Ogre][] SDK (tested with 1.7.2) and move `lib/Release/Ogre.framework` into
|
5. Download [Ogre][] SDK (tested with 1.7.2), unpack it and move
|
||||||
`Library/Frameworks`.
|
`lib/Release/Ogre.framework` into `Library/Frameworks`.
|
||||||
|
|
||||||
6. Download [OIS][] and use the XCode project provided in
|
6. Download [OIS][] and use the XCode project provided in
|
||||||
`ois/Mac/XCode-2.2`. Be sure to set your build architecture to
|
`ois/Mac/XCode-2.2`. Be sure to set your build architecture to
|
||||||
|
@ -92,6 +92,7 @@ Getting OpenMW Working
|
||||||
$ cd /path/to/open/build/dir
|
$ cd /path/to/open/build/dir
|
||||||
$ cmake \
|
$ cmake \
|
||||||
-D CMAKE_OSX_ARCHITECTURES=i386 \
|
-D CMAKE_OSX_ARCHITECTURES=i386 \
|
||||||
|
-D OGRESDK=/path/to/ogre/sdk \
|
||||||
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
|
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
|
||||||
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
|
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
|
||||||
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
|
||||||
|
@ -108,32 +109,17 @@ Getting OpenMW Working
|
||||||
You can use -G"Xcode" if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
|
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
|
if you prefer Eclipse. You also can specify -D CMAKE_BUILD_TYPE=Debug for debug
|
||||||
build.
|
build.
|
||||||
|
|
||||||
11. In build directory create directory for game resources:
|
|
||||||
$ cd /path/to/openmw/build/dir
|
|
||||||
$ mkdir Contents
|
|
||||||
$ mkdir Contents/Resources
|
|
||||||
$ mkdir Contents/Plugins
|
|
||||||
Copy Ogre plugins from Ogre SDK to Plugins subdir:
|
|
||||||
$ cp /path/to/ogre/sdk/lib/*.dylib Contents/Plugins
|
|
||||||
Create symlink to resources subdirectory:
|
|
||||||
$ ln -s resources Contents/Resources/resources
|
|
||||||
Create symlinks for *.cfg files:
|
|
||||||
$ ln -s plugins.cfg Contents/MacOS/plugins.cfg
|
|
||||||
$ ln -s openmw.cfg Contents/MacOS/openmw.cfg
|
|
||||||
|
|
||||||
12. Move your Morrowind `Data Files` directory into the `Contents/Resources`
|
11. Copy your Morrowind `Data Files` directory into the OpenMW build dir
|
||||||
with the name `data` or create symlink:
|
with the name `data` or create symlink:
|
||||||
$ ln -s /path/to/morrowind/data/files Contents/Resources/data
|
$ ln -s /path/to/morrowind/data/files /path/to/openmw/build/dir/data
|
||||||
|
|
||||||
13. From your build directory run:
|
12. From your build directory run:
|
||||||
$ ./openmw
|
$ OpenMW.app/Contents/MacOS/openmw
|
||||||
|
or:
|
||||||
|
$ open OpenMW.app
|
||||||
Enjoy!
|
Enjoy!
|
||||||
|
|
||||||
14. Optionally you can create .app bundle:
|
|
||||||
$ make package
|
|
||||||
But for now you shold manually copy Contents directory from build directory to bundle
|
|
||||||
(because there is no plugins and resources in generated .app).
|
|
||||||
|
|
||||||
|
|
||||||
[boost]: http://www.boost.org
|
[boost]: http://www.boost.org
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
CMAKE_POLICY(PUSH)
|
CMAKE_POLICY(PUSH)
|
||||||
|
|
||||||
IF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR)
|
IF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR AND OGRE_LIB_DIR AND OGRE_PLUGIN_DIR)
|
||||||
SET(OGRE_FIND_QUIETLY TRUE) # Already in cache, be silent
|
SET(OGRE_FIND_QUIETLY TRUE) # Already in cache, be silent
|
||||||
ENDIF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR)
|
ENDIF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR AND OGRE_LIB_DIR AND OGRE_PLUGIN_DIR)
|
||||||
|
|
||||||
IF (WIN32) #Windows
|
IF (WIN32) #Windows
|
||||||
MESSAGE(STATUS "Looking for OGRE")
|
MESSAGE(STATUS "Looking for OGRE")
|
||||||
|
@ -47,7 +47,16 @@ IF (UNIX AND NOT APPLE)
|
||||||
PKG_CHECK_MODULES(OGRE OGRE)
|
PKG_CHECK_MODULES(OGRE OGRE)
|
||||||
ENDIF (UNIX AND NOT APPLE)
|
ENDIF (UNIX AND NOT APPLE)
|
||||||
|
|
||||||
|
# on OS X we need Ogre SDK because framework doesn't include all libs, just Ogre Main lib
|
||||||
IF (APPLE)
|
IF (APPLE)
|
||||||
|
IF (OGRESDK)
|
||||||
|
MESSAGE(STATUS "Using Ogre SDK")
|
||||||
|
SET(OGRE_LIB_DIR ${OGRESDK}/lib)
|
||||||
|
ELSE (OGRESDK)
|
||||||
|
MESSAGE(FATAL_ERROR "Path to Ogre SDK not specified. Specify OGRESDK.")
|
||||||
|
ENDIF (OGRESDK)
|
||||||
|
|
||||||
|
|
||||||
FIND_PATH(OGRE_INCLUDE_DIR Ogre.h
|
FIND_PATH(OGRE_INCLUDE_DIR Ogre.h
|
||||||
PATHS
|
PATHS
|
||||||
/Library/Frameworks
|
/Library/Frameworks
|
||||||
|
@ -71,7 +80,12 @@ SET(OGRE_LIB_DIR ${OGRE_LIB_DIR} CACHE PATH "")
|
||||||
|
|
||||||
if(OGRE_LIB_DIR)
|
if(OGRE_LIB_DIR)
|
||||||
CMAKE_POLICY(SET CMP0009 NEW)
|
CMAKE_POLICY(SET CMP0009 NEW)
|
||||||
FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.so")
|
IF (NOT APPLE)
|
||||||
|
FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.so")
|
||||||
|
ENDIF (NOT APPLE)
|
||||||
|
IF (APPLE)
|
||||||
|
FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.dylib")
|
||||||
|
ENDIF (APPLE)
|
||||||
FOREACH (OGRE_PLUGINS_FILE ${OGRE_PLUGINS})
|
FOREACH (OGRE_PLUGINS_FILE ${OGRE_PLUGINS})
|
||||||
STRING(REGEX REPLACE "/[^/]*$" "" OGRE_PLUGIN_DIR ${OGRE_PLUGINS_FILE})
|
STRING(REGEX REPLACE "/[^/]*$" "" OGRE_PLUGIN_DIR ${OGRE_PLUGINS_FILE})
|
||||||
ENDFOREACH(OGRE_PLUGINS_FILE)
|
ENDFOREACH(OGRE_PLUGINS_FILE)
|
||||||
|
@ -85,6 +99,7 @@ IF (OGRE_FOUND)
|
||||||
IF (NOT OGRE_FIND_QUIETLY)
|
IF (NOT OGRE_FIND_QUIETLY)
|
||||||
MESSAGE(STATUS " libraries : ${OGRE_LIBRARIES} from ${OGRE_LIB_DIR}")
|
MESSAGE(STATUS " libraries : ${OGRE_LIBRARIES} from ${OGRE_LIB_DIR}")
|
||||||
MESSAGE(STATUS " includes : ${OGRE_INCLUDE_DIR}")
|
MESSAGE(STATUS " includes : ${OGRE_INCLUDE_DIR}")
|
||||||
|
MESSAGE(STATUS " plugins : ${OGRE_PLUGIN_DIR}")
|
||||||
ENDIF (NOT OGRE_FIND_QUIETLY)
|
ENDIF (NOT OGRE_FIND_QUIETLY)
|
||||||
ELSE (OGRE_FOUND)
|
ELSE (OGRE_FOUND)
|
||||||
IF (OGRE_FIND_REQUIRED)
|
IF (OGRE_FIND_REQUIRED)
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
|
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
|
||||||
typedef int32_t Color;
|
typedef int32_t Color;
|
||||||
|
|
||||||
enum VarType
|
enum VarType
|
||||||
{
|
{
|
||||||
VT_Unknown,
|
VT_Unknown,
|
||||||
VT_None,
|
VT_None,
|
||||||
VT_Short,
|
VT_Short,
|
||||||
|
@ -18,79 +19,75 @@ enum VarType
|
||||||
VT_Float,
|
VT_Float,
|
||||||
VT_String,
|
VT_String,
|
||||||
VT_Ignored
|
VT_Ignored
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Specialization
|
enum Specialization
|
||||||
{
|
{
|
||||||
SPC_Combat = 0,
|
SPC_Combat = 0, SPC_Magic = 1, SPC_Stealth = 2
|
||||||
SPC_Magic = 1,
|
};
|
||||||
SPC_Stealth = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RangeType
|
enum RangeType
|
||||||
{
|
{
|
||||||
RT_Self = 0,
|
RT_Self = 0, RT_Touch = 1, RT_Target = 2
|
||||||
RT_Touch = 1,
|
};
|
||||||
RT_Target = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A list of references to spells and spell effects. This is shared
|
/** A list of references to spells and spell effects. This is shared
|
||||||
between the records BSGN, NPC and RACE.
|
between the records BSGN, NPC and RACE.
|
||||||
*/
|
*/
|
||||||
struct SpellList
|
struct SpellList
|
||||||
{
|
{
|
||||||
std::vector<std::string> list;
|
std::vector<std::string> list;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
while(esm.isNextSub("NPCS"))
|
while (esm.isNextSub("NPCS"))
|
||||||
list.push_back(esm.getHString());
|
list.push_back(esm.getHString());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Defines a spell effect. Shared between SPEL (Spells), ALCH
|
/** Defines a spell effect. Shared between SPEL (Spells), ALCH
|
||||||
(Potions) and ENCH (Item enchantments) records
|
(Potions) and ENCH (Item enchantments) records
|
||||||
*/
|
*/
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
// Position and rotation
|
// Position and rotation
|
||||||
struct Position
|
struct Position
|
||||||
{
|
{
|
||||||
float pos[3];
|
float pos[3];
|
||||||
float rot[3];
|
float rot[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENAMstruct
|
struct ENAMstruct
|
||||||
{
|
{
|
||||||
// Magical effect, hard-coded ID
|
// Magical effect, hard-coded ID
|
||||||
short effectID;
|
short effectID;
|
||||||
|
|
||||||
// Which skills/attributes are affected (for restore/drain spells
|
// Which skills/attributes are affected (for restore/drain spells
|
||||||
// etc.)
|
// etc.)
|
||||||
signed char skill, attribute; // -1 if N/A
|
signed char skill, attribute; // -1 if N/A
|
||||||
|
|
||||||
// Other spell parameters
|
// Other spell parameters
|
||||||
int range; // 0 - self, 1 - touch, 2 - target (RangeType enum)
|
int range; // 0 - self, 1 - touch, 2 - target (RangeType enum)
|
||||||
int area, duration, magnMin, magnMax;
|
int area, duration, magnMin, magnMax;
|
||||||
|
|
||||||
// Struct size should be 24 bytes
|
// Struct size should be 24 bytes
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
struct EffectList
|
struct EffectList
|
||||||
{
|
{
|
||||||
std::vector<ENAMstruct> list;
|
std::vector<ENAMstruct> list;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
ENAMstruct s;
|
ENAMstruct s;
|
||||||
while(esm.isNextSub("ENAM"))
|
while (esm.isNextSub("ENAM"))
|
||||||
{
|
{
|
||||||
esm.getHT(s, 24);
|
esm.getHT(s, 24);
|
||||||
list.push_back(s);
|
list.push_back(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
345
components/esm/esm_reader.cpp
Normal file
345
components/esm/esm_reader.cpp
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
ESM_Context ESMReader::getContext()
|
||||||
|
{
|
||||||
|
// Update the file position before returning
|
||||||
|
mCtx.filePos = mEsm->tell();
|
||||||
|
return mCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::restoreContext(const ESM_Context &rc)
|
||||||
|
{
|
||||||
|
// Reopen the file if necessary
|
||||||
|
if (mCtx.filename != rc.filename)
|
||||||
|
openRaw(rc.filename);
|
||||||
|
|
||||||
|
// Copy the data
|
||||||
|
mCtx = rc;
|
||||||
|
|
||||||
|
// Make sure we seek to the right place
|
||||||
|
mEsm->seek(mCtx.filePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::close()
|
||||||
|
{
|
||||||
|
mEsm.reset();
|
||||||
|
mCtx.filename.clear();
|
||||||
|
mCtx.leftFile = 0;
|
||||||
|
mCtx.leftRec = 0;
|
||||||
|
mCtx.leftSub = 0;
|
||||||
|
mCtx.subCached = false;
|
||||||
|
mCtx.recName.val = 0;
|
||||||
|
mCtx.subName.val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
mEsm = _esm;
|
||||||
|
mCtx.filename = name;
|
||||||
|
mCtx.leftFile = mEsm->size();
|
||||||
|
|
||||||
|
// Flag certain files for special treatment, based on the file
|
||||||
|
// name.
|
||||||
|
const char *cstr = mCtx.filename.c_str();
|
||||||
|
if (iends(cstr, "Morrowind.esm"))
|
||||||
|
mSpf = SF_Morrowind;
|
||||||
|
else if (iends(cstr, "Tribunal.esm"))
|
||||||
|
mSpf = SF_Tribunal;
|
||||||
|
else if (iends(cstr, "Bloodmoon.esm"))
|
||||||
|
mSpf = SF_Bloodmoon;
|
||||||
|
else
|
||||||
|
mSpf = SF_Other;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::open(Mangle::Stream::StreamPtr _esm, const std::string &name)
|
||||||
|
{
|
||||||
|
openRaw(_esm, name);
|
||||||
|
|
||||||
|
if (getRecName() != "TES3")
|
||||||
|
fail("Not a valid Morrowind file");
|
||||||
|
|
||||||
|
getRecHeader();
|
||||||
|
|
||||||
|
// Get the header
|
||||||
|
getHNT(mCtx.header, "HEDR", 300);
|
||||||
|
|
||||||
|
if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13)
|
||||||
|
fail("Unsupported file format version");
|
||||||
|
|
||||||
|
while (isNextSub("MAST"))
|
||||||
|
{
|
||||||
|
MasterData m;
|
||||||
|
m.name = getHString();
|
||||||
|
m.size = getHNLong("DATA");
|
||||||
|
mMasters.push_back(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCtx.header.type == FT_ESS)
|
||||||
|
{
|
||||||
|
// Savegame-related data
|
||||||
|
|
||||||
|
// Player position etc
|
||||||
|
getHNT(mSaveData, "GMDT", 124);
|
||||||
|
|
||||||
|
/* Image properties, five ints. Is always:
|
||||||
|
Red-mask: 0xff0000
|
||||||
|
Blue-mask: 0x00ff00
|
||||||
|
Green-mask: 0x0000ff
|
||||||
|
Alpha-mask: 0x000000
|
||||||
|
Bpp: 32
|
||||||
|
*/
|
||||||
|
getSubNameIs("SCRD");
|
||||||
|
skipHSubSize(20);
|
||||||
|
|
||||||
|
/* Savegame screenshot:
|
||||||
|
128x128 pixels * 4 bytes per pixel
|
||||||
|
*/
|
||||||
|
getSubNameIs("SCRS");
|
||||||
|
skipHSubSize(65536);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::open(const std::string &file)
|
||||||
|
{
|
||||||
|
using namespace Mangle::Stream;
|
||||||
|
open(StreamPtr(new FileStream(file)), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::openRaw(const std::string &file)
|
||||||
|
{
|
||||||
|
using namespace Mangle::Stream;
|
||||||
|
openRaw(StreamPtr(new FileStream(file)), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ESMReader::getHNLong(const char *name)
|
||||||
|
{
|
||||||
|
int64_t val;
|
||||||
|
getHNT(val, name);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ESMReader::getHNOString(const char* name)
|
||||||
|
{
|
||||||
|
if (isNextSub(name))
|
||||||
|
return getHString();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ESMReader::getHNString(const char* name)
|
||||||
|
{
|
||||||
|
getSubNameIs(name);
|
||||||
|
return getHString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ESMReader::getHString()
|
||||||
|
{
|
||||||
|
getSubHeader();
|
||||||
|
|
||||||
|
// Hack to make MultiMark.esp load. Zero-length strings do not
|
||||||
|
// occur in any of the official mods, but MultiMark makes use of
|
||||||
|
// them. For some reason, they break the rules, and contain a byte
|
||||||
|
// (value 0) even if the header says there is no data. If
|
||||||
|
// Morrowind accepts it, so should we.
|
||||||
|
if (mCtx.leftSub == 0)
|
||||||
|
{
|
||||||
|
// Skip the following zero byte
|
||||||
|
mCtx.leftRec--;
|
||||||
|
char c;
|
||||||
|
mEsm->read(&c, 1);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getString(mCtx.leftSub);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::getHExact(void*p, int size)
|
||||||
|
{
|
||||||
|
getSubHeader();
|
||||||
|
if (size != static_cast<int> (mCtx.leftSub))
|
||||||
|
fail("getHExact() size mismatch");
|
||||||
|
getExact(p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the given number of bytes from a named subrecord
|
||||||
|
void ESMReader::getHNExact(void*p, int size, const char* name)
|
||||||
|
{
|
||||||
|
getSubNameIs(name);
|
||||||
|
getHExact(p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next subrecord name and check if it matches the parameter
|
||||||
|
void ESMReader::getSubNameIs(const char* name)
|
||||||
|
{
|
||||||
|
getSubName();
|
||||||
|
if (mCtx.subName != name)
|
||||||
|
fail(
|
||||||
|
"Expected subrecord " + std::string(name) + " but got "
|
||||||
|
+ mCtx.subName.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ESMReader::isNextSub(const char* name)
|
||||||
|
{
|
||||||
|
if (!mCtx.leftRec)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
getSubName();
|
||||||
|
|
||||||
|
// If the name didn't match, then mark the it as 'cached' so it's
|
||||||
|
// available for the next call to getSubName.
|
||||||
|
mCtx.subCached = (mCtx.subName != name);
|
||||||
|
|
||||||
|
// If subCached is false, then subName == name.
|
||||||
|
return !mCtx.subCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read subrecord name. This gets called a LOT, so I've optimized it
|
||||||
|
// slightly.
|
||||||
|
void ESMReader::getSubName()
|
||||||
|
{
|
||||||
|
// If the name has already been read, do nothing
|
||||||
|
if (mCtx.subCached)
|
||||||
|
{
|
||||||
|
mCtx.subCached = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reading the subrecord data anyway.
|
||||||
|
mEsm->read(mCtx.subName.name, 4);
|
||||||
|
mCtx.leftRec -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ESMReader::isEmptyOrGetName()
|
||||||
|
{
|
||||||
|
if (mCtx.leftRec)
|
||||||
|
{
|
||||||
|
mEsm->read(mCtx.subName.name, 4);
|
||||||
|
mCtx.leftRec -= 4;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::skipHSub()
|
||||||
|
{
|
||||||
|
getSubHeader();
|
||||||
|
skip(mCtx.leftSub);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::skipHSubSize(int size)
|
||||||
|
{
|
||||||
|
skipHSub();
|
||||||
|
if (static_cast<int> (mCtx.leftSub) != size)
|
||||||
|
fail("skipHSubSize() mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::getSubHeader()
|
||||||
|
{
|
||||||
|
if (mCtx.leftRec < 4)
|
||||||
|
fail("End of record while reading sub-record header");
|
||||||
|
|
||||||
|
// Get subrecord size
|
||||||
|
getT(mCtx.leftSub);
|
||||||
|
|
||||||
|
// Adjust number of record bytes left
|
||||||
|
mCtx.leftRec -= mCtx.leftSub + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::getSubHeaderIs(int size)
|
||||||
|
{
|
||||||
|
getSubHeader();
|
||||||
|
if (size != static_cast<int> (mCtx.leftSub))
|
||||||
|
fail("getSubHeaderIs(): Sub header mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
NAME ESMReader::getRecName()
|
||||||
|
{
|
||||||
|
if (!hasMoreRecs())
|
||||||
|
fail("No more records, getRecName() failed");
|
||||||
|
getName(mCtx.recName);
|
||||||
|
mCtx.leftFile -= 4;
|
||||||
|
|
||||||
|
// Make sure we don't carry over any old cached subrecord
|
||||||
|
// names. This can happen in some cases when we skip parts of a
|
||||||
|
// record.
|
||||||
|
mCtx.subCached = false;
|
||||||
|
|
||||||
|
return mCtx.recName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::skipRecord()
|
||||||
|
{
|
||||||
|
skip(mCtx.leftRec);
|
||||||
|
mCtx.leftRec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::skipHRecord()
|
||||||
|
{
|
||||||
|
if (!mCtx.leftFile)
|
||||||
|
return;
|
||||||
|
getRecHeader();
|
||||||
|
skipRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::getRecHeader(uint32_t &flags)
|
||||||
|
{
|
||||||
|
// General error checking
|
||||||
|
if (mCtx.leftFile < 12)
|
||||||
|
fail("End of file while reading record header");
|
||||||
|
if (mCtx.leftRec)
|
||||||
|
fail("Previous record contains unread bytes");
|
||||||
|
|
||||||
|
getUint(mCtx.leftRec);
|
||||||
|
getUint(flags);// This header entry is always zero
|
||||||
|
getUint(flags);
|
||||||
|
mCtx.leftFile -= 12;
|
||||||
|
|
||||||
|
// Check that sizes add up
|
||||||
|
if (mCtx.leftFile < mCtx.leftRec)
|
||||||
|
fail("Record size is larger than rest of file");
|
||||||
|
|
||||||
|
// Adjust number of bytes mCtx.left in file
|
||||||
|
mCtx.leftFile -= mCtx.leftRec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Lowest level data reading and misc methods
|
||||||
|
*
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
void ESMReader::getExact(void*x, int size)
|
||||||
|
{
|
||||||
|
int t = mEsm->read(x, size);
|
||||||
|
if (t != size)
|
||||||
|
fail("Read error");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ESMReader::getString(int size)
|
||||||
|
{
|
||||||
|
char *ptr = ToUTF8::getBuffer(size);
|
||||||
|
mEsm->read(ptr, size);
|
||||||
|
|
||||||
|
// Convert to UTF8 and return
|
||||||
|
return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMReader::fail(const std::string &msg)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
stringstream ss;
|
||||||
|
|
||||||
|
ss << "ESM Error: " << msg;
|
||||||
|
ss << "\n File: " << mCtx.filename;
|
||||||
|
ss << "\n Record: " << mCtx.recName.toString();
|
||||||
|
ss << "\n Subrecord: " << mCtx.subName.toString();
|
||||||
|
if (mEsm != NULL)
|
||||||
|
ss << "\n Offset: 0x" << hex << mEsm->tell();
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -171,122 +171,27 @@ public:
|
||||||
/** Save the current file position and information in a ESM_Context
|
/** Save the current file position and information in a ESM_Context
|
||||||
struct
|
struct
|
||||||
*/
|
*/
|
||||||
ESM_Context getContext()
|
ESM_Context getContext();
|
||||||
{
|
|
||||||
// Update the file position before returning
|
|
||||||
mCtx.filePos = mEsm->tell();
|
|
||||||
return mCtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Restore a previously saved context */
|
/** Restore a previously saved context */
|
||||||
void restoreContext(const ESM_Context &rc)
|
void restoreContext(const ESM_Context &rc);
|
||||||
{
|
|
||||||
// Reopen the file if necessary
|
|
||||||
if(mCtx.filename != rc.filename)
|
|
||||||
openRaw(rc.filename);
|
|
||||||
|
|
||||||
// Copy the data
|
|
||||||
mCtx = rc;
|
|
||||||
|
|
||||||
// Make sure we seek to the right place
|
|
||||||
mEsm->seek(mCtx.filePos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Close the file, resets all information. After calling close()
|
/** Close the file, resets all information. After calling close()
|
||||||
the structure may be reused to load a new file.
|
the structure may be reused to load a new file.
|
||||||
*/
|
*/
|
||||||
void close()
|
void close();
|
||||||
{
|
|
||||||
mEsm.reset();
|
|
||||||
mCtx.filename.clear();
|
|
||||||
mCtx.leftFile = 0;
|
|
||||||
mCtx.leftRec = 0;
|
|
||||||
mCtx.leftSub = 0;
|
|
||||||
mCtx.subCached = false;
|
|
||||||
mCtx.recName.val = 0;
|
|
||||||
mCtx.subName.val = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Raw opening. Opens the file and sets everything up but doesn't
|
/// Raw opening. Opens the file and sets everything up but doesn't
|
||||||
/// parse the header.
|
/// parse the header.
|
||||||
void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name)
|
void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name);
|
||||||
{
|
|
||||||
close();
|
|
||||||
mEsm = _esm;
|
|
||||||
mCtx.filename = name;
|
|
||||||
mCtx.leftFile = mEsm->size();
|
|
||||||
|
|
||||||
// Flag certain files for special treatment, based on the file
|
|
||||||
// name.
|
|
||||||
const char *cstr = mCtx.filename.c_str();
|
|
||||||
if(iends(cstr, "Morrowind.esm")) mSpf = SF_Morrowind;
|
|
||||||
else if(iends(cstr, "Tribunal.esm")) mSpf = SF_Tribunal;
|
|
||||||
else if(iends(cstr, "Bloodmoon.esm")) mSpf = SF_Bloodmoon;
|
|
||||||
else mSpf = SF_Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load ES file from a new stream, parses the header. Closes the
|
/// Load ES file from a new stream, parses the header. Closes the
|
||||||
/// currently open file first, if any.
|
/// currently open file first, if any.
|
||||||
void open(Mangle::Stream::StreamPtr _esm, const std::string &name)
|
void open(Mangle::Stream::StreamPtr _esm, const std::string &name);
|
||||||
{
|
|
||||||
openRaw(_esm, name);
|
|
||||||
|
|
||||||
if(getRecName() != "TES3")
|
void open(const std::string &file);
|
||||||
fail("Not a valid Morrowind file");
|
|
||||||
|
|
||||||
getRecHeader();
|
void openRaw(const std::string &file);
|
||||||
|
|
||||||
// Get the header
|
|
||||||
getHNT(mCtx.header, "HEDR", 300);
|
|
||||||
|
|
||||||
if(mCtx.header.version != VER_12 &&
|
|
||||||
mCtx.header.version != VER_13)
|
|
||||||
fail("Unsupported file format version");
|
|
||||||
|
|
||||||
while(isNextSub("MAST"))
|
|
||||||
{
|
|
||||||
MasterData m;
|
|
||||||
m.name = getHString();
|
|
||||||
m.size = getHNLong("DATA");
|
|
||||||
mMasters.push_back(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mCtx.header.type == FT_ESS)
|
|
||||||
{
|
|
||||||
// Savegame-related data
|
|
||||||
|
|
||||||
// Player position etc
|
|
||||||
getHNT(mSaveData, "GMDT", 124);
|
|
||||||
|
|
||||||
/* Image properties, five ints. Is always:
|
|
||||||
Red-mask: 0xff0000
|
|
||||||
Blue-mask: 0x00ff00
|
|
||||||
Green-mask: 0x0000ff
|
|
||||||
Alpha-mask: 0x000000
|
|
||||||
Bpp: 32
|
|
||||||
*/
|
|
||||||
getSubNameIs("SCRD");
|
|
||||||
skipHSubSize(20);
|
|
||||||
|
|
||||||
/* Savegame screenshot:
|
|
||||||
128x128 pixels * 4 bytes per pixel
|
|
||||||
*/
|
|
||||||
getSubNameIs("SCRS");
|
|
||||||
skipHSubSize(65536);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void open(const std::string &file)
|
|
||||||
{
|
|
||||||
using namespace Mangle::Stream;
|
|
||||||
open(StreamPtr(new FileStream(file)), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void openRaw(const std::string &file)
|
|
||||||
{
|
|
||||||
using namespace Mangle::Stream;
|
|
||||||
openRaw(StreamPtr(new FileStream(file)), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
*
|
*
|
||||||
|
@ -306,8 +211,8 @@ public:
|
||||||
template <typename X>
|
template <typename X>
|
||||||
void getHNOT(X &x, const char* name)
|
void getHNOT(X &x, const char* name)
|
||||||
{
|
{
|
||||||
if(isNextSub(name))
|
if(isNextSub(name))
|
||||||
getHT(x);
|
getHT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version with extra size checking, to make sure the compiler
|
// Version with extra size checking, to make sure the compiler
|
||||||
|
@ -315,26 +220,21 @@ public:
|
||||||
template <typename X>
|
template <typename X>
|
||||||
void getHNT(X &x, const char* name, int size)
|
void getHNT(X &x, const char* name, int size)
|
||||||
{
|
{
|
||||||
assert(sizeof(X) == size);
|
assert(sizeof(X) == size);
|
||||||
getSubNameIs(name);
|
getSubNameIs(name);
|
||||||
getHT(x);
|
getHT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t getHNLong(const char *name)
|
int64_t getHNLong(const char *name);
|
||||||
{
|
|
||||||
int64_t val;
|
|
||||||
getHNT(val, name);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get data of a given type/size, including subrecord header
|
// Get data of a given type/size, including subrecord header
|
||||||
template <typename X>
|
template <typename X>
|
||||||
void getHT(X &x)
|
void getHT(X &x)
|
||||||
{
|
{
|
||||||
getSubHeader();
|
getSubHeader();
|
||||||
if(mCtx.leftSub != sizeof(X))
|
if (mCtx.leftSub != sizeof(X))
|
||||||
fail("getHT(): subrecord size mismatch");
|
fail("getHT(): subrecord size mismatch");
|
||||||
getT(x);
|
getT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version with extra size checking, to make sure the compiler
|
// Version with extra size checking, to make sure the compiler
|
||||||
|
@ -342,62 +242,24 @@ public:
|
||||||
template <typename X>
|
template <typename X>
|
||||||
void getHT(X &x, int size)
|
void getHT(X &x, int size)
|
||||||
{
|
{
|
||||||
assert(sizeof(X) == size);
|
assert(sizeof(X) == size);
|
||||||
getHT(x);
|
getHT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a string by the given name if it is the next record.
|
// Read a string by the given name if it is the next record.
|
||||||
std::string getHNOString(const char* name)
|
std::string getHNOString(const char* name);
|
||||||
{
|
|
||||||
if(isNextSub(name))
|
|
||||||
return getHString();
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a string with the given sub-record name
|
// Read a string with the given sub-record name
|
||||||
std::string getHNString(const char* name)
|
std::string getHNString(const char* name);
|
||||||
{
|
|
||||||
getSubNameIs(name);
|
|
||||||
return getHString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a string, including the sub-record header (but not the name)
|
// Read a string, including the sub-record header (but not the name)
|
||||||
std::string getHString()
|
std::string getHString();
|
||||||
{
|
|
||||||
getSubHeader();
|
|
||||||
|
|
||||||
// Hack to make MultiMark.esp load. Zero-length strings do not
|
|
||||||
// occur in any of the official mods, but MultiMark makes use of
|
|
||||||
// them. For some reason, they break the rules, and contain a byte
|
|
||||||
// (value 0) even if the header says there is no data. If
|
|
||||||
// Morrowind accepts it, so should we.
|
|
||||||
if(mCtx.leftSub == 0)
|
|
||||||
{
|
|
||||||
// Skip the following zero byte
|
|
||||||
mCtx.leftRec--;
|
|
||||||
char c;
|
|
||||||
mEsm->read(&c,1);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return getString(mCtx.leftSub);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the given number of bytes from a subrecord
|
// Read the given number of bytes from a subrecord
|
||||||
void getHExact(void*p, int size)
|
void getHExact(void*p, int size);
|
||||||
{
|
|
||||||
getSubHeader();
|
|
||||||
if(size !=static_cast<int> (mCtx.leftSub))
|
|
||||||
fail("getHExact() size mismatch");
|
|
||||||
getExact(p,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the given number of bytes from a named subrecord
|
// Read the given number of bytes from a named subrecord
|
||||||
void getHNExact(void*p, int size, const char* name)
|
void getHNExact(void*p, int size, const char* name);
|
||||||
{
|
|
||||||
getSubNameIs(name);
|
|
||||||
getHExact(p,size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
*
|
*
|
||||||
|
@ -406,100 +268,37 @@ public:
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
// Get the next subrecord name and check if it matches the parameter
|
// Get the next subrecord name and check if it matches the parameter
|
||||||
void getSubNameIs(const char* name)
|
void getSubNameIs(const char* name);
|
||||||
{
|
|
||||||
getSubName();
|
|
||||||
if(mCtx.subName != name)
|
|
||||||
fail("Expected subrecord " + std::string(name) + " but got " + mCtx.subName.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks if the next sub record name matches the parameter. If it
|
/** Checks if the next sub record name matches the parameter. If it
|
||||||
does, it is read into 'subName' just as if getSubName() was
|
does, it is read into 'subName' just as if getSubName() was
|
||||||
called. If not, the read name will still be available for future
|
called. If not, the read name will still be available for future
|
||||||
calls to getSubName(), isNextSub() and getSubNameIs().
|
calls to getSubName(), isNextSub() and getSubNameIs().
|
||||||
*/
|
*/
|
||||||
bool isNextSub(const char* name)
|
bool isNextSub(const char* name);
|
||||||
{
|
|
||||||
if(!mCtx.leftRec) return false;
|
|
||||||
|
|
||||||
getSubName();
|
|
||||||
|
|
||||||
// If the name didn't match, then mark the it as 'cached' so it's
|
|
||||||
// available for the next call to getSubName.
|
|
||||||
mCtx.subCached = (mCtx.subName != name);
|
|
||||||
|
|
||||||
// If subCached is false, then subName == name.
|
|
||||||
return !mCtx.subCached;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read subrecord name. This gets called a LOT, so I've optimized it
|
// Read subrecord name. This gets called a LOT, so I've optimized it
|
||||||
// slightly.
|
// slightly.
|
||||||
void getSubName()
|
void getSubName();
|
||||||
{
|
|
||||||
// If the name has already been read, do nothing
|
|
||||||
if(mCtx.subCached)
|
|
||||||
{
|
|
||||||
mCtx.subCached = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't bother with error checking, we will catch an EOF upon
|
|
||||||
// reading the subrecord data anyway.
|
|
||||||
mEsm->read(mCtx.subName.name, 4);
|
|
||||||
mCtx.leftRec -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is specially optimized for LoadINFO.
|
// This is specially optimized for LoadINFO.
|
||||||
bool isEmptyOrGetName()
|
bool isEmptyOrGetName();
|
||||||
{
|
|
||||||
if(mCtx.leftRec)
|
|
||||||
{
|
|
||||||
mEsm->read(mCtx.subName.name, 4);
|
|
||||||
mCtx.leftRec -= 4;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip current sub record, including header (but not including
|
// Skip current sub record, including header (but not including
|
||||||
// name.)
|
// name.)
|
||||||
void skipHSub()
|
void skipHSub();
|
||||||
{
|
|
||||||
getSubHeader();
|
|
||||||
skip(mCtx.leftSub);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip sub record and check its size
|
// Skip sub record and check its size
|
||||||
void skipHSubSize(int size)
|
void skipHSubSize(int size);
|
||||||
{
|
|
||||||
skipHSub();
|
|
||||||
if(static_cast<int> (mCtx.leftSub) != size)
|
|
||||||
fail("skipHSubSize() mismatch");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sub-record header. This updates leftRec beyond the current
|
/* Sub-record header. This updates leftRec beyond the current
|
||||||
sub-record as well. leftSub contains size of current sub-record.
|
sub-record as well. leftSub contains size of current sub-record.
|
||||||
*/
|
*/
|
||||||
void getSubHeader()
|
void getSubHeader();
|
||||||
{
|
|
||||||
if(mCtx.leftRec < 4)
|
|
||||||
fail("End of record while reading sub-record header");
|
|
||||||
|
|
||||||
// Get subrecord size
|
|
||||||
getT(mCtx.leftSub);
|
|
||||||
|
|
||||||
// Adjust number of record bytes left
|
|
||||||
mCtx.leftRec -= mCtx.leftSub + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get sub header and check the size
|
/** Get sub header and check the size
|
||||||
*/
|
*/
|
||||||
void getSubHeaderIs(int size)
|
void getSubHeaderIs(int size);
|
||||||
{
|
|
||||||
getSubHeader();
|
|
||||||
if(size != static_cast<int> (mCtx.leftSub))
|
|
||||||
fail("getSubHeaderIs(): Sub header mismatch");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
*
|
*
|
||||||
|
@ -508,62 +307,21 @@ public:
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
// Get the next record name
|
// Get the next record name
|
||||||
NAME getRecName()
|
NAME getRecName();
|
||||||
{
|
|
||||||
if(!hasMoreRecs())
|
|
||||||
fail("No more records, getRecName() failed");
|
|
||||||
getName(mCtx.recName);
|
|
||||||
mCtx.leftFile -= 4;
|
|
||||||
|
|
||||||
// Make sure we don't carry over any old cached subrecord
|
|
||||||
// names. This can happen in some cases when we skip parts of a
|
|
||||||
// record.
|
|
||||||
mCtx.subCached = false;
|
|
||||||
|
|
||||||
return mCtx.recName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the rest of this record. Assumes the name and header have
|
// Skip the rest of this record. Assumes the name and header have
|
||||||
// already been read
|
// already been read
|
||||||
void skipRecord()
|
void skipRecord();
|
||||||
{
|
|
||||||
skip(mCtx.leftRec);
|
|
||||||
mCtx.leftRec = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip an entire record, including the header (but not the name)
|
// Skip an entire record, including the header (but not the name)
|
||||||
void skipHRecord()
|
void skipHRecord();
|
||||||
{
|
|
||||||
if(!mCtx.leftFile) return;
|
|
||||||
getRecHeader();
|
|
||||||
skipRecord();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read record header. This updatesleftFile BEYOND the data that
|
/* Read record header. This updatesleftFile BEYOND the data that
|
||||||
follows the header, ie beyond the entire record. You should use
|
follows the header, ie beyond the entire record. You should use
|
||||||
leftRec to orient yourself inside the record itself.
|
leftRec to orient yourself inside the record itself.
|
||||||
*/
|
*/
|
||||||
void getRecHeader() { uint32_t u; getRecHeader(u); }
|
void getRecHeader() { uint32_t u; getRecHeader(u); }
|
||||||
void getRecHeader(uint32_t &flags)
|
void getRecHeader(uint32_t &flags);
|
||||||
{
|
|
||||||
// General error checking
|
|
||||||
if(mCtx.leftFile < 12)
|
|
||||||
fail("End of file while reading record header");
|
|
||||||
if(mCtx.leftRec)
|
|
||||||
fail("Previous record contains unread bytes");
|
|
||||||
|
|
||||||
getUint(mCtx.leftRec);
|
|
||||||
getUint(flags);// This header entry is always zero
|
|
||||||
getUint(flags);
|
|
||||||
mCtx.leftFile -= 12;
|
|
||||||
|
|
||||||
// Check that sizes add up
|
|
||||||
if(mCtx.leftFile < mCtx.leftRec)
|
|
||||||
fail("Record size is larger than rest of file");
|
|
||||||
|
|
||||||
// Adjust number of bytes mCtx.left in file
|
|
||||||
mCtx.leftFile -= mCtx.leftRec;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasMoreRecs() { return mCtx.leftFile > 0; }
|
bool hasMoreRecs() { return mCtx.leftFile > 0; }
|
||||||
bool hasMoreSubs() { return mCtx.leftRec > 0; }
|
bool hasMoreSubs() { return mCtx.leftRec > 0; }
|
||||||
|
@ -578,44 +336,19 @@ public:
|
||||||
template <typename X>
|
template <typename X>
|
||||||
void getT(X &x) { getExact(&x, sizeof(X)); }
|
void getT(X &x) { getExact(&x, sizeof(X)); }
|
||||||
|
|
||||||
void getExact(void*x, int size)
|
void getExact(void*x, int size);
|
||||||
{
|
|
||||||
int t = mEsm->read(x, size);
|
|
||||||
if(t != size)
|
|
||||||
fail("Read error");
|
|
||||||
}
|
|
||||||
void getName(NAME &name) { getT(name); }
|
void getName(NAME &name) { getT(name); }
|
||||||
void getUint(uint32_t &u) { getT(u); }
|
void getUint(uint32_t &u) { getT(u); }
|
||||||
|
|
||||||
// Read the next 'size' bytes and return them as a string. Converts
|
// Read the next 'size' bytes and return them as a string. Converts
|
||||||
// them from native encoding to UTF8 in the process.
|
// them from native encoding to UTF8 in the process.
|
||||||
std::string getString(int size)
|
std::string getString(int size);
|
||||||
{
|
|
||||||
char *ptr = ToUTF8::getBuffer(size);
|
|
||||||
mEsm->read(ptr,size);
|
|
||||||
|
|
||||||
// Convert to UTF8 and return
|
|
||||||
return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252);
|
|
||||||
}
|
|
||||||
|
|
||||||
void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
|
void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
|
||||||
uint64_t getOffset() { return mEsm->tell(); }
|
uint64_t getOffset() { return mEsm->tell(); }
|
||||||
|
|
||||||
/// Used for error handling
|
/// Used for error handling
|
||||||
void fail(const std::string &msg)
|
void fail(const std::string &msg);
|
||||||
{
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
stringstream ss;
|
|
||||||
|
|
||||||
ss << "ESM Error: " << msg;
|
|
||||||
ss << "\n File: " << mCtx.filename;
|
|
||||||
ss << "\n Record: " << mCtx.recName.toString();
|
|
||||||
ss << "\n Subrecord: " << mCtx.subName.toString();
|
|
||||||
if(mEsm != NULL)
|
|
||||||
ss << "\n Offset: 0x" << hex << mEsm->tell();
|
|
||||||
throw std::runtime_error(ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mangle::Stream::StreamPtr mEsm;
|
Mangle::Stream::StreamPtr mEsm;
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
#include "records.hpp"
|
|
||||||
|
|
||||||
/** Implementation for some of the load() functions. Most are found in
|
|
||||||
the header files themselves, but this is a bit irritating to
|
|
||||||
compile if you're changing the functions often, as virtually the
|
|
||||||
entire engine depends on these headers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace ESM
|
|
||||||
{
|
|
||||||
void NPC::load(ESMReader &esm, const std::string& id)
|
|
||||||
{
|
|
||||||
mId = id;
|
|
||||||
|
|
||||||
npdt52.gold = -10;
|
|
||||||
|
|
||||||
model = esm.getHNOString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
|
|
||||||
race = esm.getHNString("RNAM");
|
|
||||||
cls = esm.getHNString("CNAM");
|
|
||||||
faction = esm.getHNString("ANAM");
|
|
||||||
head = esm.getHNString("BNAM");
|
|
||||||
hair = esm.getHNString("KNAM");
|
|
||||||
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
|
|
||||||
esm.getSubNameIs("NPDT");
|
|
||||||
esm.getSubHeader();
|
|
||||||
if(esm.getSubSize() == 52) esm.getExact(&npdt52, 52);
|
|
||||||
else if(esm.getSubSize() == 12) esm.getExact(&npdt12, 12);
|
|
||||||
else esm.fail("NPC_NPDT must be 12 or 52 bytes long");
|
|
||||||
|
|
||||||
esm.getHNT(flags, "FLAG");
|
|
||||||
|
|
||||||
inventory.load(esm);
|
|
||||||
spells.load(esm);
|
|
||||||
|
|
||||||
if(esm.isNextSub("AIDT"))
|
|
||||||
{
|
|
||||||
esm.getHExact(&AI, sizeof(AI));
|
|
||||||
hasAI = true;
|
|
||||||
}
|
|
||||||
else hasAI = false;
|
|
||||||
|
|
||||||
esm.skipRecord();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DialInfo::load(ESMReader &esm)
|
|
||||||
{
|
|
||||||
id = esm.getHNString("INAM");
|
|
||||||
prev = esm.getHNString("PNAM");
|
|
||||||
next = esm.getHNString("NNAM");
|
|
||||||
|
|
||||||
// Not present if deleted
|
|
||||||
if(esm.isNextSub("DATA"))
|
|
||||||
esm.getHT(data, 12);
|
|
||||||
|
|
||||||
// What follows is somewhat spaghetti-ish, but it's worth if for
|
|
||||||
// an extra speedup. INFO is by far the most common record type.
|
|
||||||
|
|
||||||
// subName is a reference to the original, so it changes whenever
|
|
||||||
// a new sub name is read. esm.isEmptyOrGetName() will get the
|
|
||||||
// next name for us, or return true if there are no more records.
|
|
||||||
esm.getSubName();
|
|
||||||
const NAME &subName = esm.retSubName();
|
|
||||||
|
|
||||||
if(subName.val == REC_ONAM)
|
|
||||||
{
|
|
||||||
actor = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_RNAM)
|
|
||||||
{
|
|
||||||
race = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_CNAM)
|
|
||||||
{
|
|
||||||
clas = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
factionLess = false;
|
|
||||||
if(subName.val == REC_FNAM)
|
|
||||||
{
|
|
||||||
npcFaction = esm.getHString();
|
|
||||||
if(npcFaction == "FFFF") factionLess = true;
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_ANAM)
|
|
||||||
{
|
|
||||||
cell = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_DNAM)
|
|
||||||
{
|
|
||||||
pcFaction = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_SNAM)
|
|
||||||
{
|
|
||||||
sound = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_NAME)
|
|
||||||
{
|
|
||||||
response = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(subName.val == REC_SCVR)
|
|
||||||
{
|
|
||||||
SelectStruct ss;
|
|
||||||
|
|
||||||
ss.selectRule = esm.getHString();
|
|
||||||
esm.isEmptyOrGetName();
|
|
||||||
|
|
||||||
if(subName.val == REC_INTV)
|
|
||||||
{
|
|
||||||
ss.type = VT_Int;
|
|
||||||
esm.getHT(ss.i);
|
|
||||||
}
|
|
||||||
else if(subName.val == REC_FLTV)
|
|
||||||
{
|
|
||||||
ss.type = VT_Float;
|
|
||||||
esm.getHT(ss.f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
esm.fail("INFO.SCVR must precede INTV or FLTV, not "
|
|
||||||
+ subName.toString());
|
|
||||||
|
|
||||||
selects.push_back(ss);
|
|
||||||
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(subName.val == REC_BNAM)
|
|
||||||
{
|
|
||||||
resultScript = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
questStatus = QS_None;
|
|
||||||
|
|
||||||
if (subName.val == REC_QSTN) questStatus = QS_Name;
|
|
||||||
else if(subName.val == REC_QSTF) questStatus = QS_Finished;
|
|
||||||
else if(subName.val == REC_QSTR) questStatus = QS_Restart;
|
|
||||||
else if(subName.val == REC_DELE) questStatus = QS_Deleted;
|
|
||||||
else
|
|
||||||
esm.fail("Don't know what to do with " + subName.toString() + " in INFO " + id);
|
|
||||||
|
|
||||||
if(questStatus != QS_None)
|
|
||||||
// Skip rest of record
|
|
||||||
esm.skipRecord();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::load(ESMReader &esm)
|
|
||||||
{
|
|
||||||
sound = esm.getHNString("FNAM");
|
|
||||||
esm.getHNT(data, "DATA", 3);
|
|
||||||
/*
|
|
||||||
cout << "vol=" << (int)data.volume
|
|
||||||
<< " min=" << (int)data.minRange
|
|
||||||
<< " max=" << (int)data.maxRange
|
|
||||||
<< endl;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
11
components/esm/loadacti.cpp
Normal file
11
components/esm/loadacti.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "loadacti.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
void Activator::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,18 +3,14 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct Activator
|
struct Activator
|
||||||
{
|
{
|
||||||
std::string name, script, model;
|
std::string name, script, model;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
14
components/esm/loadalch.cpp
Normal file
14
components/esm/loadalch.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "loadalch.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
void Potion::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
icon = esm.getHNOString("TEXT"); // not ITEX here for some reason
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(data, "ALDT", 12);
|
||||||
|
effects.load(esm);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alchemy item (potions)
|
* Alchemy item (potions)
|
||||||
|
@ -12,26 +13,18 @@ namespace ESM {
|
||||||
|
|
||||||
struct Potion
|
struct Potion
|
||||||
{
|
{
|
||||||
struct ALDTstruct
|
struct ALDTstruct
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
int autoCalc;
|
int autoCalc;
|
||||||
};
|
};
|
||||||
ALDTstruct data;
|
ALDTstruct data;
|
||||||
|
|
||||||
std::string name, model, icon, script;
|
std::string name, model, icon, script;
|
||||||
EffectList effects;
|
EffectList effects;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
icon = esm.getHNOString("TEXT"); // not ITEX here for some reason
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(data, "ALDT", 12);
|
|
||||||
effects.load(esm);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
13
components/esm/loadappa.cpp
Normal file
13
components/esm/loadappa.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "loadappa.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
void Apparatus::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
esm.getHNT(data, "AADT", 16);
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNString("ITEX");
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alchemist apparatus
|
* Alchemist apparatus
|
||||||
|
@ -11,33 +12,23 @@ namespace ESM {
|
||||||
|
|
||||||
struct Apparatus
|
struct Apparatus
|
||||||
{
|
{
|
||||||
enum AppaType
|
enum AppaType
|
||||||
{
|
{
|
||||||
MortarPestle = 0,
|
MortarPestle = 0, Albemic = 1, Calcinator = 2, Retort = 3
|
||||||
Albemic = 1,
|
|
||||||
Calcinator = 2,
|
|
||||||
Retort = 3
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AADTstruct
|
struct AADTstruct
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
float quality;
|
float quality;
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
AADTstruct data;
|
AADTstruct data;
|
||||||
std::string model, icon, script, name;
|
std::string model, icon, script, name;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
esm.getHNT(data, "AADT", 16);
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNString("ITEX");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
28
components/esm/loadarmo.cpp
Normal file
28
components/esm/loadarmo.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include "loadarmo.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void PartReferenceList::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("INDX"))
|
||||||
|
{
|
||||||
|
PartReference pr;
|
||||||
|
esm.getHT(pr.part); // The INDX byte
|
||||||
|
pr.male = esm.getHNOString("BNAM");
|
||||||
|
pr.female = esm.getHNOString("CNAM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Armor::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
esm.getHNT(data, "AODT", 24);
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
parts.load(esm);
|
||||||
|
enchant = esm.getHNOString("ENAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,102 +3,85 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
enum PartReferenceType
|
enum PartReferenceType
|
||||||
{
|
{
|
||||||
PRT_Head = 0,
|
PRT_Head = 0,
|
||||||
PRT_Hair = 1,
|
PRT_Hair = 1,
|
||||||
PRT_Neck = 2,
|
PRT_Neck = 2,
|
||||||
PRT_Cuirass = 3,
|
PRT_Cuirass = 3,
|
||||||
PRT_Groin = 4,
|
PRT_Groin = 4,
|
||||||
PRT_Skirt = 5,
|
PRT_Skirt = 5,
|
||||||
PRT_RHand = 6,
|
PRT_RHand = 6,
|
||||||
PRT_LHand = 7,
|
PRT_LHand = 7,
|
||||||
PRT_RWrist = 8,
|
PRT_RWrist = 8,
|
||||||
PRT_LWrist = 9,
|
PRT_LWrist = 9,
|
||||||
PRT_Shield = 10,
|
PRT_Shield = 10,
|
||||||
PRT_RForearm = 11,
|
PRT_RForearm = 11,
|
||||||
PRT_LForearm = 12,
|
PRT_LForearm = 12,
|
||||||
PRT_RUpperarm = 13,
|
PRT_RUpperarm = 13,
|
||||||
PRT_LUpperarm = 14,
|
PRT_LUpperarm = 14,
|
||||||
PRT_RFoot = 15,
|
PRT_RFoot = 15,
|
||||||
PRT_LFoot = 16,
|
PRT_LFoot = 16,
|
||||||
PRT_RAnkle = 17,
|
PRT_RAnkle = 17,
|
||||||
PRT_LAnkle = 18,
|
PRT_LAnkle = 18,
|
||||||
PRT_RKnee = 19,
|
PRT_RKnee = 19,
|
||||||
PRT_LKnee = 20,
|
PRT_LKnee = 20,
|
||||||
PRT_RLeg = 21,
|
PRT_RLeg = 21,
|
||||||
PRT_LLeg = 22,
|
PRT_LLeg = 22,
|
||||||
PRT_RPauldron = 23,
|
PRT_RPauldron = 23,
|
||||||
PRT_LPauldron = 24,
|
PRT_LPauldron = 24,
|
||||||
PRT_Weapon = 25,
|
PRT_Weapon = 25,
|
||||||
PRT_Tail = 26
|
PRT_Tail = 26
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reference to body parts
|
// Reference to body parts
|
||||||
struct PartReference
|
struct PartReference
|
||||||
{
|
{
|
||||||
char part;
|
char part;
|
||||||
std::string male, female;
|
std::string male, female;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A list of references to body parts
|
// A list of references to body parts
|
||||||
struct PartReferenceList
|
struct PartReferenceList
|
||||||
{
|
{
|
||||||
std::vector<PartReference> parts;
|
std::vector<PartReference> parts;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
while(esm.isNextSub("INDX"))
|
|
||||||
{
|
|
||||||
PartReference pr;
|
|
||||||
esm.getHT(pr.part); // The INDX byte
|
|
||||||
pr.male = esm.getHNOString("BNAM");
|
|
||||||
pr.female = esm.getHNOString("CNAM");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Armor
|
struct Armor
|
||||||
{
|
{
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Helmet = 0,
|
Helmet = 0,
|
||||||
Cuirass = 1,
|
Cuirass = 1,
|
||||||
LPauldron = 2,
|
LPauldron = 2,
|
||||||
RPauldron = 3,
|
RPauldron = 3,
|
||||||
Greaves = 4,
|
Greaves = 4,
|
||||||
Boots = 5,
|
Boots = 5,
|
||||||
LGauntlet = 6,
|
LGauntlet = 6,
|
||||||
RGauntlet = 7,
|
RGauntlet = 7,
|
||||||
Shield = 8,
|
Shield = 8,
|
||||||
LBracer = 9,
|
LBracer = 9,
|
||||||
RBracer = 10
|
RBracer = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AODTstruct
|
struct AODTstruct
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
float weight;
|
float weight;
|
||||||
int value, health, enchant, armor;
|
int value, health, enchant, armor;
|
||||||
};
|
};
|
||||||
|
|
||||||
AODTstruct data;
|
AODTstruct data;
|
||||||
PartReferenceList parts;
|
PartReferenceList parts;
|
||||||
|
|
||||||
std::string name, model, icon, script, enchant;
|
std::string name, model, icon, script, enchant;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
esm.getHNT(data, "AODT", 24);
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
parts.load(esm);
|
|
||||||
enchant = esm.getHNOString("ENAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
13
components/esm/loadbody.cpp
Normal file
13
components/esm/loadbody.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "loadbody.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void BodyPart::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
esm.getHNT(data, "BYDT", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,59 +3,52 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct BodyPart
|
struct BodyPart
|
||||||
{
|
{
|
||||||
enum MeshPart
|
enum MeshPart
|
||||||
{
|
{
|
||||||
MP_Head = 0,
|
MP_Head = 0,
|
||||||
MP_Hair = 1,
|
MP_Hair = 1,
|
||||||
MP_Neck = 2,
|
MP_Neck = 2,
|
||||||
MP_Chest = 3,
|
MP_Chest = 3,
|
||||||
MP_Groin = 4,
|
MP_Groin = 4,
|
||||||
MP_Hand = 5,
|
MP_Hand = 5,
|
||||||
MP_Wrist = 6,
|
MP_Wrist = 6,
|
||||||
MP_Forearm = 7,
|
MP_Forearm = 7,
|
||||||
MP_Upperarm = 8,
|
MP_Upperarm = 8,
|
||||||
MP_Foot = 9,
|
MP_Foot = 9,
|
||||||
MP_Ankle = 10,
|
MP_Ankle = 10,
|
||||||
MP_Knee = 11,
|
MP_Knee = 11,
|
||||||
MP_Upperleg = 12,
|
MP_Upperleg = 12,
|
||||||
MP_Clavicle = 13,
|
MP_Clavicle = 13,
|
||||||
MP_Tail = 14
|
MP_Tail = 14
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
BPF_Female = 1,
|
BPF_Female = 1, BPF_Playable = 2
|
||||||
BPF_Playable = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MeshType
|
enum MeshType
|
||||||
{
|
{
|
||||||
MT_Skin = 0,
|
MT_Skin = 0, MT_Clothing = 1, MT_Armor = 2
|
||||||
MT_Clothing = 1,
|
|
||||||
MT_Armor = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BYDTstruct
|
struct BYDTstruct
|
||||||
{
|
{
|
||||||
char part;
|
char part;
|
||||||
char vampire;
|
char vampire;
|
||||||
char flags;
|
char flags;
|
||||||
char type;
|
char type;
|
||||||
};
|
};
|
||||||
|
|
||||||
BYDTstruct data;
|
BYDTstruct data;
|
||||||
std::string model, name;
|
std::string model, name;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
esm.getHNT(data, "BYDT", 4);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
17
components/esm/loadbook.cpp
Normal file
17
components/esm/loadbook.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include "loadbook.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Book::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(data, "BKDT", 20);
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
text = esm.getHNOString("TEXT");
|
||||||
|
enchant = esm.getHNOString("ENAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Books, magic scrolls, notes and so on
|
* Books, magic scrolls, notes and so on
|
||||||
|
@ -11,25 +12,16 @@ namespace ESM {
|
||||||
|
|
||||||
struct Book
|
struct Book
|
||||||
{
|
{
|
||||||
struct BKDTstruct
|
struct BKDTstruct
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value, isScroll, skillID, enchant;
|
int value, isScroll, skillID, enchant;
|
||||||
};
|
};
|
||||||
|
|
||||||
BKDTstruct data;
|
BKDTstruct data;
|
||||||
std::string name, model, icon, script, enchant, text;
|
std::string name, model, icon, script, enchant, text;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(data, "BKDT", 20);
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
text = esm.getHNOString("TEXT");
|
|
||||||
enchant = esm.getHNOString("ENAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
15
components/esm/loadbsgn.cpp
Normal file
15
components/esm/loadbsgn.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "loadbsgn.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void BirthSign::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
texture = esm.getHNOString("TNAM");
|
||||||
|
description = esm.getHNOString("DESC");
|
||||||
|
|
||||||
|
powers.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,23 +4,17 @@
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct BirthSign
|
struct BirthSign
|
||||||
{
|
{
|
||||||
std::string name, description, texture;
|
std::string name, description, texture;
|
||||||
|
|
||||||
// List of powers and abilities that come with this birth sign.
|
// List of powers and abilities that come with this birth sign.
|
||||||
SpellList powers;
|
SpellList powers;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
texture = esm.getHNOString("TNAM");
|
|
||||||
description = esm.getHNOString("DESC");
|
|
||||||
|
|
||||||
powers.load(esm);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
113
components/esm/loadcell.cpp
Normal file
113
components/esm/loadcell.cpp
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
#include "loadcell.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Cell::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
// Ignore this for now, it might mean we should delete the entire
|
||||||
|
// cell?
|
||||||
|
if (esm.isNextSub("DELE"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
esm.getHNT(data, "DATA", 12);
|
||||||
|
|
||||||
|
// Water level
|
||||||
|
water = 0;
|
||||||
|
|
||||||
|
if (data.flags & Interior)
|
||||||
|
{
|
||||||
|
// Interior cells
|
||||||
|
|
||||||
|
if (esm.isNextSub("INTV") || esm.isNextSub("WHGT"))
|
||||||
|
esm.getHT(water);
|
||||||
|
|
||||||
|
// Quasi-exterior cells have a region (which determines the
|
||||||
|
// weather), pure interior cells have ambient lighting
|
||||||
|
// instead.
|
||||||
|
if (data.flags & QuasiEx)
|
||||||
|
region = esm.getHNOString("RGNN");
|
||||||
|
else
|
||||||
|
esm.getHNT(ambi, "AMBI", 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Exterior cells
|
||||||
|
region = esm.getHNOString("RGNN");
|
||||||
|
esm.getHNOT(mapColor, "NAM5");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save position of the cell references and move on
|
||||||
|
context = esm.getContext();
|
||||||
|
esm.skipRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cell::restore(ESMReader &esm) const
|
||||||
|
{
|
||||||
|
esm.restoreContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
|
||||||
|
{
|
||||||
|
if (!esm.hasMoreSubs())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Number of references in the cell? Maximum once in each cell,
|
||||||
|
// but not always at the beginning, and not always right. In other
|
||||||
|
// words, completely useless.
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
esm.getHNOT(i, "NAM0");
|
||||||
|
}
|
||||||
|
|
||||||
|
esm.getHNT(ref.refnum, "FRMR");
|
||||||
|
ref.refID = esm.getHNString("NAME");
|
||||||
|
|
||||||
|
// getHNOT will not change the existing value if the subrecord is
|
||||||
|
// missing
|
||||||
|
ref.scale = 1.0;
|
||||||
|
esm.getHNOT(ref.scale, "XSCL");
|
||||||
|
|
||||||
|
ref.owner = esm.getHNOString("ANAM");
|
||||||
|
ref.glob = esm.getHNOString("BNAM");
|
||||||
|
ref.soul = esm.getHNOString("XSOL");
|
||||||
|
|
||||||
|
ref.faction = esm.getHNOString("CNAM");
|
||||||
|
ref.factIndex = -1;
|
||||||
|
esm.getHNOT(ref.factIndex, "INDX");
|
||||||
|
|
||||||
|
ref.charge = -1.0;
|
||||||
|
esm.getHNOT(ref.charge, "XCHG");
|
||||||
|
|
||||||
|
ref.intv = 0;
|
||||||
|
ref.nam9 = 0;
|
||||||
|
esm.getHNOT(ref.intv, "INTV");
|
||||||
|
esm.getHNOT(ref.nam9, "NAM9");
|
||||||
|
|
||||||
|
// Present for doors that teleport you to another cell.
|
||||||
|
if (esm.isNextSub("DODT"))
|
||||||
|
{
|
||||||
|
ref.teleport = true;
|
||||||
|
esm.getHT(ref.doorDest);
|
||||||
|
ref.destCell = esm.getHNOString("DNAM");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ref.teleport = false;
|
||||||
|
|
||||||
|
// Integer, despite the name suggesting otherwise
|
||||||
|
ref.lockLevel = 0;
|
||||||
|
esm.getHNOT(ref.lockLevel, "FLTV");
|
||||||
|
ref.key = esm.getHNOString("KNAM");
|
||||||
|
ref.trap = esm.getHNOString("TNAM");
|
||||||
|
|
||||||
|
ref.unam = 0;
|
||||||
|
ref.fltv = 0;
|
||||||
|
esm.getHNOT(ref.unam, "UNAM");
|
||||||
|
esm.getHNOT(ref.fltv, "FLTV");
|
||||||
|
|
||||||
|
esm.getHNT(ref.pos, "DATA", 24);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -117,51 +117,14 @@ struct Cell
|
||||||
int water; // Water level
|
int water; // Water level
|
||||||
int mapColor;
|
int mapColor;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
// Ignore this for now, it might mean we should delete the entire
|
|
||||||
// cell?
|
|
||||||
if(esm.isNextSub("DELE")) esm.skipHSub();
|
|
||||||
|
|
||||||
esm.getHNT(data, "DATA", 12);
|
|
||||||
|
|
||||||
// Water level
|
|
||||||
water = 0;
|
|
||||||
|
|
||||||
if(data.flags & Interior)
|
|
||||||
{
|
|
||||||
// Interior cells
|
|
||||||
|
|
||||||
if(esm.isNextSub("INTV") || esm.isNextSub("WHGT"))
|
|
||||||
esm.getHT(water);
|
|
||||||
|
|
||||||
// Quasi-exterior cells have a region (which determines the
|
|
||||||
// weather), pure interior cells have ambient lighting
|
|
||||||
// instead.
|
|
||||||
if(data.flags & QuasiEx)
|
|
||||||
region = esm.getHNOString("RGNN");
|
|
||||||
else
|
|
||||||
esm.getHNT(ambi, "AMBI", 16);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Exterior cells
|
|
||||||
region = esm.getHNOString("RGNN");
|
|
||||||
esm.getHNOT(mapColor, "NAM5");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save position of the cell references and move on
|
|
||||||
context = esm.getContext();
|
|
||||||
esm.skipRecord();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the given reader to the stored position. Will try to open
|
// Restore the given reader to the stored position. Will try to open
|
||||||
// the file matching the stored file name. If you want to read from
|
// the file matching the stored file name. If you want to read from
|
||||||
// somewhere other than the file system, you need to pre-open the
|
// somewhere other than the file system, you need to pre-open the
|
||||||
// ESMReader, and the filename must match the stored filename
|
// ESMReader, and the filename must match the stored filename
|
||||||
// exactly.
|
// exactly.
|
||||||
void restore(ESMReader &esm) const
|
void restore(ESMReader &esm) const;
|
||||||
{ esm.restoreContext(context); }
|
|
||||||
|
|
||||||
/* Get the next reference in this cell, if any. Returns false when
|
/* Get the next reference in this cell, if any. Returns false when
|
||||||
there are no more references in the cell.
|
there are no more references in the cell.
|
||||||
|
@ -169,66 +132,7 @@ struct Cell
|
||||||
All fields of the CellRef struct are overwritten. You can safely
|
All fields of the CellRef struct are overwritten. You can safely
|
||||||
reuse one memory location without blanking it between calls.
|
reuse one memory location without blanking it between calls.
|
||||||
*/
|
*/
|
||||||
static bool getNextRef(ESMReader &esm, CellRef &ref)
|
static bool getNextRef(ESMReader &esm, CellRef &ref);
|
||||||
{
|
|
||||||
if(!esm.hasMoreSubs()) return false;
|
|
||||||
|
|
||||||
// Number of references in the cell? Maximum once in each cell,
|
|
||||||
// but not always at the beginning, and not always right. In other
|
|
||||||
// words, completely useless.
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
esm.getHNOT(i, "NAM0");
|
|
||||||
}
|
|
||||||
|
|
||||||
esm.getHNT(ref.refnum, "FRMR");
|
|
||||||
ref.refID = esm.getHNString("NAME");
|
|
||||||
|
|
||||||
// getHNOT will not change the existing value if the subrecord is
|
|
||||||
// missing
|
|
||||||
ref.scale = 1.0;
|
|
||||||
esm.getHNOT(ref.scale, "XSCL");
|
|
||||||
|
|
||||||
ref.owner = esm.getHNOString("ANAM");
|
|
||||||
ref.glob = esm.getHNOString("BNAM");
|
|
||||||
ref.soul = esm.getHNOString("XSOL");
|
|
||||||
|
|
||||||
ref.faction = esm.getHNOString("CNAM");
|
|
||||||
ref.factIndex = -1;
|
|
||||||
esm.getHNOT(ref.factIndex, "INDX");
|
|
||||||
|
|
||||||
ref.charge = -1.0;
|
|
||||||
esm.getHNOT(ref.charge, "XCHG");
|
|
||||||
|
|
||||||
ref.intv = 0;
|
|
||||||
ref.nam9 = 0;
|
|
||||||
esm.getHNOT(ref.intv, "INTV");
|
|
||||||
esm.getHNOT(ref.nam9, "NAM9");
|
|
||||||
|
|
||||||
// Present for doors that teleport you to another cell.
|
|
||||||
if(esm.isNextSub("DODT"))
|
|
||||||
{
|
|
||||||
ref.teleport = true;
|
|
||||||
esm.getHT(ref.doorDest);
|
|
||||||
ref.destCell = esm.getHNOString("DNAM");
|
|
||||||
}
|
|
||||||
else ref.teleport = false;
|
|
||||||
|
|
||||||
// Integer, despite the name suggesting otherwise
|
|
||||||
ref.lockLevel = 0;
|
|
||||||
esm.getHNOT(ref.lockLevel, "FLTV");
|
|
||||||
ref.key = esm.getHNOString("KNAM");
|
|
||||||
ref.trap = esm.getHNOString("TNAM");
|
|
||||||
|
|
||||||
ref.unam = 0;
|
|
||||||
ref.fltv = 0;
|
|
||||||
esm.getHNOT(ref.unam, "UNAM");
|
|
||||||
esm.getHNOT(ref.fltv, "FLTV");
|
|
||||||
|
|
||||||
esm.getHNT(ref.pos, "DATA", 24);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "loadclas.hpp"
|
#include "loadclas.hpp"
|
||||||
|
|
||||||
using namespace ESM;
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
const Class::Specialization Class::specializationIds[3] = {
|
const Class::Specialization Class::specializationIds[3] = {
|
||||||
Class::Combat,
|
Class::Combat,
|
||||||
|
@ -13,3 +14,16 @@ const char *Class::gmstSpecializationIds[3] = {
|
||||||
"sSpecializationMagic",
|
"sSpecializationMagic",
|
||||||
"sSpecializationStealth"
|
"sSpecializationStealth"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Class::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
esm.getHNT(data, "CLDT", 60);
|
||||||
|
|
||||||
|
if (data.isPlayable > 1)
|
||||||
|
esm.fail("Unknown bool value");
|
||||||
|
|
||||||
|
description = esm.getHNOString("DESC");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Character class definitions
|
* Character class definitions
|
||||||
|
@ -13,62 +14,51 @@ namespace ESM {
|
||||||
// class
|
// class
|
||||||
struct Class
|
struct Class
|
||||||
{
|
{
|
||||||
enum AutoCalc
|
enum AutoCalc
|
||||||
{
|
{
|
||||||
Weapon = 0x00001,
|
Weapon = 0x00001,
|
||||||
Armor = 0x00002,
|
Armor = 0x00002,
|
||||||
Clothing = 0x00004,
|
Clothing = 0x00004,
|
||||||
Books = 0x00008,
|
Books = 0x00008,
|
||||||
Ingredient = 0x00010,
|
Ingredient = 0x00010,
|
||||||
Lockpick = 0x00020,
|
Lockpick = 0x00020,
|
||||||
Probe = 0x00040,
|
Probe = 0x00040,
|
||||||
Lights = 0x00080,
|
Lights = 0x00080,
|
||||||
Apparatus = 0x00100,
|
Apparatus = 0x00100,
|
||||||
Repair = 0x00200,
|
Repair = 0x00200,
|
||||||
Misc = 0x00400,
|
Misc = 0x00400,
|
||||||
Spells = 0x00800,
|
Spells = 0x00800,
|
||||||
MagicItems = 0x01000,
|
MagicItems = 0x01000,
|
||||||
Potions = 0x02000,
|
Potions = 0x02000,
|
||||||
Training = 0x04000,
|
Training = 0x04000,
|
||||||
Spellmaking = 0x08000,
|
Spellmaking = 0x08000,
|
||||||
Enchanting = 0x10000,
|
Enchanting = 0x10000,
|
||||||
RepairItem = 0x20000
|
RepairItem = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Specialization
|
enum Specialization
|
||||||
{
|
{
|
||||||
Combat = 0,
|
Combat = 0, Magic = 1, Stealth = 2
|
||||||
Magic = 1,
|
|
||||||
Stealth = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Specialization specializationIds[3];
|
static const Specialization specializationIds[3];
|
||||||
static const char *gmstSpecializationIds[3];
|
static const char *gmstSpecializationIds[3];
|
||||||
|
|
||||||
struct CLDTstruct
|
struct CLDTstruct
|
||||||
{
|
|
||||||
int attribute[2]; // Attributes that get class bonus
|
|
||||||
int specialization; // 0 = Combat, 1 = Magic, 2 = Stealth
|
|
||||||
int skills[5][2]; // Minor and major skills.
|
|
||||||
int isPlayable; // 0x0001 - Playable class
|
|
||||||
|
|
||||||
// I have no idea how to autocalculate these items...
|
|
||||||
int calc;
|
|
||||||
}; // 60 bytes
|
|
||||||
|
|
||||||
std::string name, description;
|
|
||||||
CLDTstruct data;
|
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
|
||||||
{
|
{
|
||||||
name = esm.getHNString("FNAM");
|
int attribute[2]; // Attributes that get class bonus
|
||||||
esm.getHNT(data, "CLDT", 60);
|
int specialization; // 0 = Combat, 1 = Magic, 2 = Stealth
|
||||||
|
int skills[5][2]; // Minor and major skills.
|
||||||
|
int isPlayable; // 0x0001 - Playable class
|
||||||
|
|
||||||
if(data.isPlayable > 1)
|
// I have no idea how to autocalculate these items...
|
||||||
esm.fail("Unknown bool value");
|
int calc;
|
||||||
|
}; // 60 bytes
|
||||||
|
|
||||||
description = esm.getHNOString("DESC");
|
std::string name, description;
|
||||||
}
|
CLDTstruct data;
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
20
components/esm/loadclot.cpp
Normal file
20
components/esm/loadclot.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "loadclot.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Clothing::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(data, "CTDT", 12);
|
||||||
|
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
|
||||||
|
parts.load(esm);
|
||||||
|
|
||||||
|
enchant = esm.getHNOString("ENAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "loadarmo.hpp"
|
#include "loadarmo.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clothing
|
* Clothing
|
||||||
|
@ -12,46 +13,34 @@ namespace ESM {
|
||||||
|
|
||||||
struct Clothing
|
struct Clothing
|
||||||
{
|
{
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Pants = 0,
|
Pants = 0,
|
||||||
Shoes = 1,
|
Shoes = 1,
|
||||||
Shirt = 2,
|
Shirt = 2,
|
||||||
Belt = 3,
|
Belt = 3,
|
||||||
Robe = 4,
|
Robe = 4,
|
||||||
RGlove = 5,
|
RGlove = 5,
|
||||||
LGlove = 6,
|
LGlove = 6,
|
||||||
Skirt = 7,
|
Skirt = 7,
|
||||||
Ring = 8,
|
Ring = 8,
|
||||||
Amulet = 9
|
Amulet = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CTDTstruct
|
struct CTDTstruct
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
float weight;
|
float weight;
|
||||||
short value;
|
short value;
|
||||||
short enchant;
|
short enchant;
|
||||||
};
|
};
|
||||||
CTDTstruct data;
|
CTDTstruct data;
|
||||||
|
|
||||||
PartReferenceList parts;
|
PartReferenceList parts;
|
||||||
|
|
||||||
std::string name, model, icon, enchant, script;
|
std::string name, model, icon, enchant, script;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(data, "CTDT", 12);
|
|
||||||
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
|
|
||||||
parts.load(esm);
|
|
||||||
|
|
||||||
enchant = esm.getHNOString("ENAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
33
components/esm/loadcont.cpp
Normal file
33
components/esm/loadcont.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "loadcont.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void InventoryList::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
ContItem ci;
|
||||||
|
while (esm.isNextSub("NPCO"))
|
||||||
|
{
|
||||||
|
esm.getHT(ci, 36);
|
||||||
|
list.push_back(ci);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Container::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(weight, "CNDT", 4);
|
||||||
|
esm.getHNT(flags, "FLAG", 4);
|
||||||
|
|
||||||
|
if (flags & 0xf4)
|
||||||
|
esm.fail("Unknown flags");
|
||||||
|
if (!(flags & 0x8))
|
||||||
|
esm.fail("Flag 8 not set");
|
||||||
|
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
|
||||||
|
inventory.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Container definition
|
* Container definition
|
||||||
|
@ -11,54 +12,33 @@ namespace ESM {
|
||||||
|
|
||||||
struct ContItem
|
struct ContItem
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
NAME32 item;
|
NAME32 item;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InventoryList
|
struct InventoryList
|
||||||
{
|
{
|
||||||
std::vector<ContItem> list;
|
std::vector<ContItem> list;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
ContItem ci;
|
|
||||||
while(esm.isNextSub("NPCO"))
|
|
||||||
{
|
|
||||||
esm.getHT(ci, 36);
|
|
||||||
list.push_back(ci);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Container
|
struct Container
|
||||||
{
|
{
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
Organic = 1, // Objects cannot be placed in this container
|
Organic = 1, // Objects cannot be placed in this container
|
||||||
Respawn = 2, // Respawns after 4 months
|
Respawn = 2, // Respawns after 4 months
|
||||||
Unknown = 8
|
Unknown = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name, model, script;
|
std::string name, model, script;
|
||||||
|
|
||||||
float weight; // Not sure, might be max total weight allowed?
|
float weight; // Not sure, might be max total weight allowed?
|
||||||
int flags;
|
int flags;
|
||||||
InventoryList inventory;
|
InventoryList inventory;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(weight, "CNDT", 4);
|
|
||||||
esm.getHNT(flags, "FLAG", 4);
|
|
||||||
|
|
||||||
if(flags & 0xf4) esm.fail("Unknown flags");
|
|
||||||
if(!(flags & 0x8)) esm.fail("Flag 8 not set");
|
|
||||||
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
|
|
||||||
inventory.load(esm);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
40
components/esm/loadcrea.cpp
Normal file
40
components/esm/loadcrea.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "loadcrea.hpp"
|
||||||
|
|
||||||
|
namespace ESM {
|
||||||
|
|
||||||
|
void Creature::load(ESMReader &esm, const std::string& id)
|
||||||
|
{
|
||||||
|
mId = id;
|
||||||
|
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
original = esm.getHNOString("CNAM");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
|
||||||
|
esm.getHNT(data, "NPDT", 96);
|
||||||
|
|
||||||
|
esm.getHNT(flags, "FLAG");
|
||||||
|
scale = 1.0;
|
||||||
|
esm.getHNOT(scale, "XSCL");
|
||||||
|
|
||||||
|
inventory.load(esm);
|
||||||
|
|
||||||
|
// More subrecords:
|
||||||
|
|
||||||
|
// AIDT - data (12 bytes, unknown)
|
||||||
|
// AI_W - wander (14 bytes, i don't understand it)
|
||||||
|
// short distance
|
||||||
|
// byte duration
|
||||||
|
// byte timeOfDay
|
||||||
|
// byte idle[10]
|
||||||
|
//
|
||||||
|
// Rest is optional:
|
||||||
|
// AI_T - travel?
|
||||||
|
// AI_F - follow?
|
||||||
|
// AI_E - escort?
|
||||||
|
// AI_A - activate?
|
||||||
|
|
||||||
|
esm.skipRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "loadcont.hpp"
|
#include "loadcont.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creature definition
|
* Creature definition
|
||||||
|
@ -13,91 +14,53 @@ namespace ESM {
|
||||||
|
|
||||||
struct Creature
|
struct Creature
|
||||||
{
|
{
|
||||||
// Default is 0x48?
|
// Default is 0x48?
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
Biped = 0x001,
|
Biped = 0x001, Respawn = 0x002, Weapon = 0x004, // Has weapon and shield
|
||||||
Respawn = 0x002,
|
None = 0x008, // ??
|
||||||
Weapon = 0x004, // Has weapon and shield
|
Swims = 0x010,
|
||||||
None = 0x008, // ??
|
Flies = 0x020, // Don't know what happens if several
|
||||||
Swims = 0x010,
|
Walks = 0x040, // of these are set
|
||||||
Flies = 0x020, // Don't know what happens if several
|
Essential = 0x080,
|
||||||
Walks = 0x040, // of these are set
|
Skeleton = 0x400, // Does not have normal blood
|
||||||
Essential = 0x080,
|
Metal = 0x800
|
||||||
Skeleton = 0x400, // Does not have normal blood
|
// Has 'golden' blood
|
||||||
Metal = 0x800 // Has 'golden' blood
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Creatures = 0,
|
Creatures = 0, Deadra = 1, Undead = 2, Humanoid = 3
|
||||||
Deadra = 1,
|
|
||||||
Undead = 2,
|
|
||||||
Humanoid = 3
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NPDTstruct
|
struct NPDTstruct
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
// For creatures we obviously have to use ints, not shorts and
|
// For creatures we obviously have to use ints, not shorts and
|
||||||
// bytes like we use for NPCs.... this file format just makes so
|
// bytes like we use for NPCs.... this file format just makes so
|
||||||
// much sense! (Still, _much_ easier to decode than the NIFs.)
|
// much sense! (Still, _much_ easier to decode than the NIFs.)
|
||||||
int level;
|
int level;
|
||||||
int strength, intelligence, willpower, agility, speed, endurance,
|
int strength, intelligence, willpower, agility, speed, endurance,
|
||||||
personality, luck, health, mana, fatigue; // Stats
|
personality, luck, health, mana, fatigue; // Stats
|
||||||
int soul; // The creatures soul value (used with soul gems.)
|
int soul; // The creatures soul value (used with soul gems.)
|
||||||
int combat, magic, stealth; // Don't know yet.
|
int combat, magic, stealth; // Don't know yet.
|
||||||
int attack[6]; // AttackMin1, AttackMax1, ditto2, ditto3
|
int attack[6]; // AttackMin1, AttackMax1, ditto2, ditto3
|
||||||
int gold;
|
int gold;
|
||||||
}; // 96 bytes
|
}; // 96 bytes
|
||||||
|
|
||||||
NPDTstruct data;
|
NPDTstruct data;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
std::string model, name, script,
|
std::string model, name, script, original; // Base creature that this is a modification of
|
||||||
original; // Base creature that this is a modification of
|
|
||||||
|
|
||||||
// Defined in loadcont.hpp
|
// Defined in loadcont.hpp
|
||||||
InventoryList inventory;
|
InventoryList inventory;
|
||||||
|
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
|
||||||
void load(ESMReader &esm, const std::string& id)
|
void load(ESMReader &esm, const std::string& id);
|
||||||
{
|
|
||||||
mId = id;
|
|
||||||
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
original = esm.getHNOString("CNAM");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
|
|
||||||
esm.getHNT(data, "NPDT", 96);
|
|
||||||
|
|
||||||
esm.getHNT(flags, "FLAG");
|
|
||||||
scale = 1.0;
|
|
||||||
esm.getHNOT(scale, "XSCL");
|
|
||||||
|
|
||||||
inventory.load(esm);
|
|
||||||
|
|
||||||
// More subrecords:
|
|
||||||
|
|
||||||
// AIDT - data (12 bytes, unknown)
|
|
||||||
// AI_W - wander (14 bytes, i don't understand it)
|
|
||||||
// short distance
|
|
||||||
// byte duration
|
|
||||||
// byte timeOfDay
|
|
||||||
// byte idle[10]
|
|
||||||
//
|
|
||||||
// Rest is optional:
|
|
||||||
// AI_T - travel?
|
|
||||||
// AI_F - follow?
|
|
||||||
// AI_E - escort?
|
|
||||||
// AI_A - activate?
|
|
||||||
|
|
||||||
esm.skipRecord();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
25
components/esm/loaddial.cpp
Normal file
25
components/esm/loaddial.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "loaddial.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Dialogue::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getSubNameIs("DATA");
|
||||||
|
esm.getSubHeader();
|
||||||
|
int si = esm.getSubSize();
|
||||||
|
if (si == 1)
|
||||||
|
esm.getT(type);
|
||||||
|
else if (si == 4)
|
||||||
|
{
|
||||||
|
// These are just markers, their values are not used.
|
||||||
|
int i;
|
||||||
|
esm.getT(i);
|
||||||
|
esm.getHNT(i, "DELE");
|
||||||
|
type = Deleted;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esm.fail("Unknown sub record size");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,8 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "loadinfo.hpp"
|
#include "loadinfo.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dialogue topic and journal entries. The actual data is contained in
|
* Dialogue topic and journal entries. The actual data is contained in
|
||||||
|
@ -15,36 +16,20 @@ namespace ESM {
|
||||||
|
|
||||||
struct Dialogue
|
struct Dialogue
|
||||||
{
|
{
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Topic = 0,
|
Topic = 0,
|
||||||
Voice = 1,
|
Voice = 1,
|
||||||
Greeting = 2,
|
Greeting = 2,
|
||||||
Persuasion = 3,
|
Persuasion = 3,
|
||||||
Journal = 4,
|
Journal = 4,
|
||||||
Deleted = -1
|
Deleted = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
char type;
|
char type;
|
||||||
std::vector<DialInfo> mInfo;
|
std::vector<DialInfo> mInfo;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getSubNameIs("DATA");
|
|
||||||
esm.getSubHeader();
|
|
||||||
int si = esm.getSubSize();
|
|
||||||
if(si == 1)
|
|
||||||
esm.getT(type);
|
|
||||||
else if(si == 4)
|
|
||||||
{
|
|
||||||
// These are just markers, their values are not used.
|
|
||||||
int i;
|
|
||||||
esm.getT(i);
|
|
||||||
esm.getHNT(i,"DELE");
|
|
||||||
type = Deleted;
|
|
||||||
}
|
|
||||||
else esm.fail("Unknown sub record size");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
15
components/esm/loaddoor.cpp
Normal file
15
components/esm/loaddoor.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "loaddoor.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Door::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
openSound = esm.getHNOString("SNAM");
|
||||||
|
closeSound = esm.getHNOString("ANAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,20 +3,14 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct Door
|
struct Door
|
||||||
{
|
{
|
||||||
std::string name, model, script, openSound, closeSound;
|
std::string name, model, script, openSound, closeSound;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
openSound = esm.getHNOString("SNAM");
|
|
||||||
closeSound = esm.getHNOString("ANAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
12
components/esm/loadench.cpp
Normal file
12
components/esm/loadench.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "loadench.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Enchantment::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(data, "ENDT", 16);
|
||||||
|
effects.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,10 @@
|
||||||
#define _ESM_ENCH_H
|
#define _ESM_ENCH_H
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enchantments
|
* Enchantments
|
||||||
|
@ -11,31 +13,27 @@ namespace ESM {
|
||||||
|
|
||||||
struct Enchantment
|
struct Enchantment
|
||||||
{
|
{
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
CastOnce = 0,
|
CastOnce = 0,
|
||||||
WhenStrikes = 1,
|
WhenStrikes = 1,
|
||||||
WhenUsed = 2,
|
WhenUsed = 2,
|
||||||
ConstantEffect = 3
|
ConstantEffect = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ENDTstruct
|
struct ENDTstruct
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
int cost;
|
int cost;
|
||||||
int charge;
|
int charge;
|
||||||
int autocalc; // Guessing this is 1 if we are supposed to auto
|
int autocalc; // Guessing this is 1 if we are supposed to auto
|
||||||
// calculate
|
// calculate
|
||||||
};
|
};
|
||||||
|
|
||||||
ENDTstruct data;
|
ENDTstruct data;
|
||||||
EffectList effects;
|
EffectList effects;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(data, "ENDT", 16);
|
|
||||||
effects.load(esm);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
31
components/esm/loadfact.cpp
Normal file
31
components/esm/loadfact.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "loadfact.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Faction::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
|
||||||
|
// Read rank names. These are optional.
|
||||||
|
int i = 0;
|
||||||
|
while (esm.isNextSub("RNAM") && i < 10)
|
||||||
|
ranks[i++] = esm.getHString();
|
||||||
|
|
||||||
|
// Main data struct
|
||||||
|
esm.getHNT(data, "FADT", 240);
|
||||||
|
|
||||||
|
if (data.isHidden > 1)
|
||||||
|
esm.fail("Unknown flag!");
|
||||||
|
|
||||||
|
// Read faction response values
|
||||||
|
while (esm.hasMoreSubs())
|
||||||
|
{
|
||||||
|
Reaction r;
|
||||||
|
r.faction = esm.getHNString("ANAM");
|
||||||
|
esm.getHNT(r.reaction, "INTV");
|
||||||
|
reactions.push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Faction definitions
|
* Faction definitions
|
||||||
|
@ -12,67 +13,46 @@ namespace ESM {
|
||||||
// Requirements for each rank
|
// Requirements for each rank
|
||||||
struct RankData
|
struct RankData
|
||||||
{
|
{
|
||||||
int attribute1, attribute2; // Attribute level
|
int attribute1, attribute2; // Attribute level
|
||||||
|
|
||||||
int skill1, skill2; // Skill level (faction skills given in
|
int skill1, skill2; // Skill level (faction skills given in
|
||||||
// skillID below.) You need one skill at
|
// skillID below.) You need one skill at
|
||||||
// level 'skill1' and two skills at level
|
// level 'skill1' and two skills at level
|
||||||
// 'skill2' to advance to this rank.
|
// 'skill2' to advance to this rank.
|
||||||
|
|
||||||
int factReaction; // Reaction from faction members
|
int factReaction; // Reaction from faction members
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Faction
|
struct Faction
|
||||||
{
|
{
|
||||||
std::string id, name;
|
std::string id, name;
|
||||||
|
|
||||||
struct FADTstruct
|
struct FADTstruct
|
||||||
{
|
{
|
||||||
// Which attributes we like
|
// Which attributes we like
|
||||||
int attribute1, attribute2;
|
int attribute1, attribute2;
|
||||||
|
|
||||||
RankData rankData[10];
|
RankData rankData[10];
|
||||||
|
|
||||||
int skillID[6]; // IDs of skills this faction require
|
int skillID[6]; // IDs of skills this faction require
|
||||||
int unknown; // Always -1?
|
int unknown; // Always -1?
|
||||||
int isHidden; // 1 - hidden from player
|
int isHidden; // 1 - hidden from player
|
||||||
}; // 240 bytes
|
}; // 240 bytes
|
||||||
|
|
||||||
FADTstruct data;
|
FADTstruct data;
|
||||||
|
|
||||||
struct Reaction
|
struct Reaction
|
||||||
{
|
{
|
||||||
std::string faction;
|
std::string faction;
|
||||||
int reaction;
|
int reaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Reaction> reactions;
|
std::vector<Reaction> reactions;
|
||||||
|
|
||||||
// Name of faction ranks (may be empty for NPC factions)
|
// Name of faction ranks (may be empty for NPC factions)
|
||||||
std::string ranks[10];
|
std::string ranks[10];
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
|
|
||||||
// Read rank names. These are optional.
|
|
||||||
int i = 0;
|
|
||||||
while(esm.isNextSub("RNAM") && i<10) ranks[i++] = esm.getHString();
|
|
||||||
|
|
||||||
// Main data struct
|
|
||||||
esm.getHNT(data, "FADT", 240);
|
|
||||||
|
|
||||||
if(data.isHidden > 1) esm.fail("Unknown flag!");
|
|
||||||
|
|
||||||
// Read faction response values
|
|
||||||
while(esm.hasMoreSubs())
|
|
||||||
{
|
|
||||||
Reaction r;
|
|
||||||
r.faction = esm.getHNString("ANAM");
|
|
||||||
esm.getHNT(r.reaction, "INTV");
|
|
||||||
reactions.push_back(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
24
components/esm/loadglob.cpp
Normal file
24
components/esm/loadglob.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "loadglob.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Global::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
VarType t;
|
||||||
|
std::string tmp = esm.getHNString("FNAM");
|
||||||
|
if (tmp == "s")
|
||||||
|
t = VT_Short;
|
||||||
|
else if (tmp == "l")
|
||||||
|
t = VT_Int;
|
||||||
|
else if (tmp == "f")
|
||||||
|
t = VT_Float;
|
||||||
|
else
|
||||||
|
esm.fail("Illegal global variable type " + tmp);
|
||||||
|
type = t;
|
||||||
|
|
||||||
|
// Note: Both floats and longs are represented as floats.
|
||||||
|
esm.getHNT(value, "FLTV");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,10 @@
|
||||||
#define _ESM_GLOB_H
|
#define _ESM_GLOB_H
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global script variables
|
* Global script variables
|
||||||
|
@ -11,22 +13,10 @@ namespace ESM {
|
||||||
|
|
||||||
struct Global
|
struct Global
|
||||||
{
|
{
|
||||||
unsigned value;
|
unsigned value;
|
||||||
VarType type;
|
VarType type;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
VarType t;
|
|
||||||
std::string tmp = esm.getHNString("FNAM");
|
|
||||||
if(tmp == "s") t = VT_Short;
|
|
||||||
else if(tmp == "l") t = VT_Int;
|
|
||||||
else if(tmp == "f") t = VT_Float;
|
|
||||||
else esm.fail("Illegal global variable type " + tmp);
|
|
||||||
type = t;
|
|
||||||
|
|
||||||
// Note: Both floats and longs are represented as floats.
|
|
||||||
esm.getHNT(value, "FLTV");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
172
components/esm/loadgmst.cpp
Normal file
172
components/esm/loadgmst.cpp
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#include "loadgmst.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
// Some handy macros
|
||||||
|
#define cI(s,x) { if(id == (s)) return (i == (x)); }
|
||||||
|
#define cF(s,x) { if(id == (s)) return (f == (x)); }
|
||||||
|
#define cS(s,x) { if(id == (s)) return (str == (x)); }
|
||||||
|
|
||||||
|
bool GameSetting::isDirtyTribunal()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Here, id contains the game setting name, and we check the
|
||||||
|
setting for certain values. If it matches, this is a "dirty"
|
||||||
|
entry. The correct entry (as defined in Tribunal and Bloodmoon
|
||||||
|
esms) are given in the comments. Many of the values are correct,
|
||||||
|
and are marked as 'same'. We still ignore them though, as they
|
||||||
|
are still in the wrong file and might override custom values
|
||||||
|
from other mods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
cS("sProfitValue", "Profit Value"); // 'Profit:'
|
||||||
|
cS("sEditNote", "Edit Note"); // same
|
||||||
|
cS("sDeleteNote", "Delete Note?"); // same
|
||||||
|
cS("sMaxSale", "Max Sale"); // 'Seller Max'
|
||||||
|
cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon'
|
||||||
|
cS("sTeleportDisabled",
|
||||||
|
"Teleportation magic does not work here.");// same
|
||||||
|
cS("sLevitateDisabled",
|
||||||
|
"Levitation magic does not work here."); // same
|
||||||
|
cS("sCompanionShare", "Companion Share"); // 'Share'
|
||||||
|
cS("sCompanionWarningButtonOne",
|
||||||
|
"Let the mercenary quit."); // same
|
||||||
|
cS("sCompanionWarningButtonTwo",
|
||||||
|
"Return to Companion Share display."); // same
|
||||||
|
cS("sCompanionWarningMessage",
|
||||||
|
"Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value.");
|
||||||
|
// 'Your mercenary is poorer now than when he contracted with
|
||||||
|
// you. Your mercenary will quit if you do not give him gold
|
||||||
|
// or goods to bring his Profit to a positive value.'
|
||||||
|
// [The difference here is "Profit Value" -> "Profit"]
|
||||||
|
|
||||||
|
// Strings that matches the id
|
||||||
|
cS("sEffectSummonFabricant", id);// 'Summon Fabricant'
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bloodmoon variant
|
||||||
|
bool GameSetting::isDirtyBloodmoon()
|
||||||
|
{
|
||||||
|
// Strings
|
||||||
|
cS("sWerewolfPopup", "Werewolf"); // same
|
||||||
|
cS("sWerewolfRestMessage",
|
||||||
|
"You cannot rest in werewolf form."); // same
|
||||||
|
cS("sWerewolfRefusal",
|
||||||
|
"You cannot do this as a werewolf."); // same
|
||||||
|
cS("sWerewolfAlarmMessage",
|
||||||
|
"You have been detected changing from a werewolf state.");
|
||||||
|
// 'You have been detected as a known werewolf.'
|
||||||
|
|
||||||
|
// Strings that matches the id
|
||||||
|
cS("sMagicCreature01ID", id); // 'BM_wolf_grey_summon'
|
||||||
|
cS("sMagicCreature02ID", id); // 'BM_bear_black_summon'
|
||||||
|
cS("sMagicCreature03ID", id); // 'BM_wolf_bone_summon'
|
||||||
|
cS("sMagicCreature04ID", id); // same
|
||||||
|
cS("sMagicCreature05ID", id); // same
|
||||||
|
cS("sEffectSummonCreature01", id); // 'Calf Wolf'
|
||||||
|
cS("sEffectSummonCreature02", id); // 'Calf Bear'
|
||||||
|
cS("sEffectSummonCreature03", id); // 'Summon Bonewolf'
|
||||||
|
cS("sEffectSummonCreature04", id); // same
|
||||||
|
cS("sEffectSummonCreature05", id); // same
|
||||||
|
|
||||||
|
// Integers
|
||||||
|
cI("iWereWolfBounty", 10000); // 1000
|
||||||
|
cI("iWereWolfFightMod", 100); // same
|
||||||
|
cI("iWereWolfFleeMod", 100); // same
|
||||||
|
cI("iWereWolfLevelToAttack", 20); // same
|
||||||
|
|
||||||
|
// Floats
|
||||||
|
cF("fFleeDistance", 3000); // same
|
||||||
|
cF("fCombatDistanceWerewolfMod", 0.3); // same
|
||||||
|
cF("fWereWolfFatigue", 400); // same
|
||||||
|
cF("fWereWolfEnchant", 1); // 0
|
||||||
|
cF("fWereWolfArmorer", 1); // 0
|
||||||
|
cF("fWereWolfBlock", 1); // 0
|
||||||
|
cF("fWereWolfSneak", 1); // 95
|
||||||
|
cF("fWereWolfDestruction", 1); // 0
|
||||||
|
cF("fWereWolfEndurance", 150); // same
|
||||||
|
cF("fWereWolfConjuration", 1); // 0
|
||||||
|
cF("fWereWolfRestoration", 1); // 0
|
||||||
|
cF("fWereWolfAthletics", 150); // 50
|
||||||
|
cF("fWereWolfLuck", 1); // 25
|
||||||
|
cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2
|
||||||
|
cF("fWereWolfMediumArmor", 1); // 0
|
||||||
|
cF("fWereWolfShortBlade", 1); // 0
|
||||||
|
cF("fWereWolfAcrobatics", 150); // 80
|
||||||
|
cF("fWereWolfSpeechcraft", 1); // 0
|
||||||
|
cF("fWereWolfAlteration", 1); // 0
|
||||||
|
cF("fWereWolfIllusion", 1); // 0
|
||||||
|
cF("fWereWolfLongBlade", 1); // 0
|
||||||
|
cF("fWereWolfMarksman", 1); // 0
|
||||||
|
cF("fWereWolfHandtoHand", 100); // same
|
||||||
|
cF("fWereWolfIntellegence", 1); // 0
|
||||||
|
cF("fWereWolfAlchemy", 1); // 0
|
||||||
|
cF("fWereWolfUnarmored", 100); // same
|
||||||
|
cF("fWereWolfAxe", 1); // 0
|
||||||
|
cF("fWereWolfRunMult", 1.5); // 1.3
|
||||||
|
cF("fWereWolfMagicka", 100); // same
|
||||||
|
cF("fWereWolfAgility", 150); // same
|
||||||
|
cF("fWereWolfBluntWeapon", 1); // 0
|
||||||
|
cF("fWereWolfSecurity", 1); // 0
|
||||||
|
cF("fWereWolfPersonality", 1); // 0
|
||||||
|
cF("fWereWolfMerchantile", 1); // 0
|
||||||
|
cF("fWereWolfHeavyArmor", 1); // 0
|
||||||
|
cF("fWereWolfSpear", 1); // 0
|
||||||
|
cF("fWereWolfStrength", 150); // same
|
||||||
|
cF("fWereWolfHealth", 2); // same
|
||||||
|
cF("fWereWolfMysticism", 1); // 0
|
||||||
|
cF("fWereWolfLightArmor", 1); // 0
|
||||||
|
cF("fWereWolfWillPower", 1); // 0
|
||||||
|
cF("fWereWolfSpeed", 150); // 90
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameSetting::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
assert(id != "");
|
||||||
|
|
||||||
|
dirty = false;
|
||||||
|
|
||||||
|
// We are apparently allowed to be empty
|
||||||
|
if (!esm.hasMoreSubs())
|
||||||
|
{
|
||||||
|
type = VT_None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load some data
|
||||||
|
esm.getSubName();
|
||||||
|
NAME n = esm.retSubName();
|
||||||
|
if (n == "STRV")
|
||||||
|
{
|
||||||
|
str = esm.getHString();
|
||||||
|
type = VT_String;
|
||||||
|
}
|
||||||
|
else if (n == "INTV")
|
||||||
|
{
|
||||||
|
esm.getHT(i);
|
||||||
|
type = VT_Int;
|
||||||
|
}
|
||||||
|
else if (n == "FLTV")
|
||||||
|
{
|
||||||
|
esm.getHT(f);
|
||||||
|
type = VT_Float;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esm.fail("Unwanted subrecord type");
|
||||||
|
|
||||||
|
int spf = esm.getSpecial();
|
||||||
|
|
||||||
|
// Check if this is one of the dirty values mentioned above. If it
|
||||||
|
// is, we set the dirty flag. This will ONLY work if you've set
|
||||||
|
// the 'id' string correctly before calling load().
|
||||||
|
|
||||||
|
if ((spf != SF_Tribunal && isDirtyTribunal()) || (spf != SF_Bloodmoon
|
||||||
|
&& isDirtyBloodmoon()))
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Game setting, with automatic cleaning of "dirty" entries.
|
* Game setting, with automatic cleaning of "dirty" entries.
|
||||||
|
@ -13,238 +14,75 @@ namespace ESM {
|
||||||
|
|
||||||
struct GameSetting
|
struct GameSetting
|
||||||
{
|
{
|
||||||
std::string id;
|
std::string id;
|
||||||
|
|
||||||
// One of these is used depending on the variable type
|
// One of these is used depending on the variable type
|
||||||
std::string str;
|
std::string str;
|
||||||
int i;
|
int i;
|
||||||
float f;
|
float f;
|
||||||
VarType type;
|
VarType type;
|
||||||
|
|
||||||
// Set to true if this is a 'dirty' entry which should be ignored
|
// Set to true if this is a 'dirty' entry which should be ignored
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
|
||||||
/*
|
|
||||||
These functions check if this game setting is one of the "dirty"
|
|
||||||
GMST records found in many mods. These are due to a serious bug in
|
|
||||||
the official TES3 editor. It only occurs in the newer editor
|
|
||||||
versions that came with Tribunal and Bloodmoon, and only if a
|
|
||||||
modder tries to make a mod without loading the corresponding
|
|
||||||
expansion master file. For example, if you have Tribunal installed
|
|
||||||
and try to make a mod without loading Tribunal.esm, the editor
|
|
||||||
will insert these GMST records as a replacement for the entries it
|
|
||||||
cannot find in the ESMs.
|
|
||||||
|
|
||||||
The values of these "dirty" records differ in general from their
|
|
||||||
values as defined in Tribunal.esm and Bloodmoon.esm, and are
|
|
||||||
always set to the same "default" values. Most of these values are
|
|
||||||
nonsensical, ie. changing the "Seller Max" string to "Max Sale",
|
|
||||||
or change the stats of werewolves to useless values like 1. Some
|
|
||||||
of them break certain spell effects.
|
|
||||||
|
|
||||||
It is most likely that these values are just leftover values from
|
|
||||||
an early stage of development that are inserted as default values
|
|
||||||
by the editor code. They are supposed to be overridden when the
|
|
||||||
correct esm file is loaded. When it isn't loaded however, you get
|
|
||||||
stuck with the initial value, and this gets written to every mod
|
|
||||||
by the editor, for some reason.
|
|
||||||
|
|
||||||
Bethesda themselves have fallen for this bug. If you install both
|
|
||||||
Tribunal and Bloodmoon, the updated Tribunal.esm will contain the
|
|
||||||
dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain
|
|
||||||
some of the dirty settings from Tribunal. In other words, this bug
|
|
||||||
affects the game EVEN IF YOU DO NOT USE ANY MODS!
|
|
||||||
|
|
||||||
The guys at Bethesda are well aware of this bug (and many others),
|
|
||||||
as the mod community and fan base complained about them for a long
|
|
||||||
time. But unfortunately it was never fixed.
|
|
||||||
|
|
||||||
There are several tools available to help modders remove these
|
|
||||||
records from their files, but not all modders use them, and they
|
|
||||||
really shouldn't have to. In this file we choose instead to reject
|
|
||||||
all the corrupt values at load time.
|
|
||||||
|
|
||||||
These functions checks if the current game setting is one of the
|
|
||||||
"dirty" ones as described above. TODO: I have not checked this
|
|
||||||
against other sources yet, do that later. Currently recognizes 22
|
|
||||||
values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods
|
|
||||||
(setting values other than the default "dirty" ones) are not
|
|
||||||
affected and will work correctly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Some handy macros
|
|
||||||
#define cI(s,x) { if(id == (s)) return (i == (x)); }
|
|
||||||
#define cF(s,x) { if(id == (s)) return (f == (x)); }
|
|
||||||
#define cS(s,x) { if(id == (s)) return (str == (x)); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
Checks for dirty tribunal values. These will be ignored if found
|
|
||||||
in any file except when they are found in "Tribunal.esm".
|
|
||||||
*/
|
|
||||||
bool isDirtyTribunal()
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
Here, id contains the game setting name, and we check the
|
These functions check if this game setting is one of the "dirty"
|
||||||
setting for certain values. If it matches, this is a "dirty"
|
GMST records found in many mods. These are due to a serious bug in
|
||||||
entry. The correct entry (as defined in Tribunal and Bloodmoon
|
the official TES3 editor. It only occurs in the newer editor
|
||||||
esms) are given in the comments. Many of the values are correct,
|
versions that came with Tribunal and Bloodmoon, and only if a
|
||||||
and are marked as 'same'. We still ignore them though, as they
|
modder tries to make a mod without loading the corresponding
|
||||||
are still in the wrong file and might override custom values
|
expansion master file. For example, if you have Tribunal installed
|
||||||
from other mods.
|
and try to make a mod without loading Tribunal.esm, the editor
|
||||||
*/
|
will insert these GMST records as a replacement for the entries it
|
||||||
|
cannot find in the ESMs.
|
||||||
|
|
||||||
// Strings
|
The values of these "dirty" records differ in general from their
|
||||||
cS("sProfitValue", "Profit Value"); // 'Profit:'
|
values as defined in Tribunal.esm and Bloodmoon.esm, and are
|
||||||
cS("sEditNote", "Edit Note"); // same
|
always set to the same "default" values. Most of these values are
|
||||||
cS("sDeleteNote", "Delete Note?"); // same
|
nonsensical, ie. changing the "Seller Max" string to "Max Sale",
|
||||||
cS("sMaxSale", "Max Sale"); // 'Seller Max'
|
or change the stats of werewolves to useless values like 1. Some
|
||||||
cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon'
|
of them break certain spell effects.
|
||||||
cS("sTeleportDisabled",
|
|
||||||
"Teleportation magic does not work here.");// same
|
|
||||||
cS("sLevitateDisabled",
|
|
||||||
"Levitation magic does not work here."); // same
|
|
||||||
cS("sCompanionShare", "Companion Share"); // 'Share'
|
|
||||||
cS("sCompanionWarningButtonOne",
|
|
||||||
"Let the mercenary quit."); // same
|
|
||||||
cS("sCompanionWarningButtonTwo",
|
|
||||||
"Return to Companion Share display."); // same
|
|
||||||
cS("sCompanionWarningMessage",
|
|
||||||
"Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value.");
|
|
||||||
// 'Your mercenary is poorer now than when he contracted with
|
|
||||||
// you. Your mercenary will quit if you do not give him gold
|
|
||||||
// or goods to bring his Profit to a positive value.'
|
|
||||||
// [The difference here is "Profit Value" -> "Profit"]
|
|
||||||
|
|
||||||
// Strings that matches the id
|
It is most likely that these values are just leftover values from
|
||||||
cS("sEffectSummonFabricant", id);// 'Summon Fabricant'
|
an early stage of development that are inserted as default values
|
||||||
return false;
|
by the editor code. They are supposed to be overridden when the
|
||||||
}
|
correct esm file is loaded. When it isn't loaded however, you get
|
||||||
|
stuck with the initial value, and this gets written to every mod
|
||||||
|
by the editor, for some reason.
|
||||||
|
|
||||||
// Bloodmoon variant
|
Bethesda themselves have fallen for this bug. If you install both
|
||||||
bool isDirtyBloodmoon()
|
Tribunal and Bloodmoon, the updated Tribunal.esm will contain the
|
||||||
{
|
dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain
|
||||||
// Strings
|
some of the dirty settings from Tribunal. In other words, this bug
|
||||||
cS("sWerewolfPopup", "Werewolf"); // same
|
affects the game EVEN IF YOU DO NOT USE ANY MODS!
|
||||||
cS("sWerewolfRestMessage",
|
|
||||||
"You cannot rest in werewolf form."); // same
|
|
||||||
cS("sWerewolfRefusal",
|
|
||||||
"You cannot do this as a werewolf."); // same
|
|
||||||
cS("sWerewolfAlarmMessage",
|
|
||||||
"You have been detected changing from a werewolf state.");
|
|
||||||
// 'You have been detected as a known werewolf.'
|
|
||||||
|
|
||||||
// Strings that matches the id
|
The guys at Bethesda are well aware of this bug (and many others),
|
||||||
cS("sMagicCreature01ID", id); // 'BM_wolf_grey_summon'
|
as the mod community and fan base complained about them for a long
|
||||||
cS("sMagicCreature02ID", id); // 'BM_bear_black_summon'
|
time. But unfortunately it was never fixed.
|
||||||
cS("sMagicCreature03ID", id); // 'BM_wolf_bone_summon'
|
|
||||||
cS("sMagicCreature04ID", id); // same
|
|
||||||
cS("sMagicCreature05ID", id); // same
|
|
||||||
cS("sEffectSummonCreature01", id); // 'Calf Wolf'
|
|
||||||
cS("sEffectSummonCreature02", id); // 'Calf Bear'
|
|
||||||
cS("sEffectSummonCreature03", id); // 'Summon Bonewolf'
|
|
||||||
cS("sEffectSummonCreature04", id); // same
|
|
||||||
cS("sEffectSummonCreature05", id); // same
|
|
||||||
|
|
||||||
// Integers
|
There are several tools available to help modders remove these
|
||||||
cI("iWereWolfBounty", 10000); // 1000
|
records from their files, but not all modders use them, and they
|
||||||
cI("iWereWolfFightMod", 100); // same
|
really shouldn't have to. In this file we choose instead to reject
|
||||||
cI("iWereWolfFleeMod", 100); // same
|
all the corrupt values at load time.
|
||||||
cI("iWereWolfLevelToAttack", 20); // same
|
|
||||||
|
|
||||||
// Floats
|
These functions checks if the current game setting is one of the
|
||||||
cF("fFleeDistance", 3000); // same
|
"dirty" ones as described above. TODO: I have not checked this
|
||||||
cF("fCombatDistanceWerewolfMod", 0.3); // same
|
against other sources yet, do that later. Currently recognizes 22
|
||||||
cF("fWereWolfFatigue", 400); // same
|
values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods
|
||||||
cF("fWereWolfEnchant", 1); // 0
|
(setting values other than the default "dirty" ones) are not
|
||||||
cF("fWereWolfArmorer", 1); // 0
|
affected and will work correctly.
|
||||||
cF("fWereWolfBlock", 1); // 0
|
*/
|
||||||
cF("fWereWolfSneak", 1); // 95
|
|
||||||
cF("fWereWolfDestruction", 1); // 0
|
|
||||||
cF("fWereWolfEndurance", 150); // same
|
|
||||||
cF("fWereWolfConjuration", 1); // 0
|
|
||||||
cF("fWereWolfRestoration", 1); // 0
|
|
||||||
cF("fWereWolfAthletics", 150); // 50
|
|
||||||
cF("fWereWolfLuck", 1); // 25
|
|
||||||
cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2
|
|
||||||
cF("fWereWolfMediumArmor", 1); // 0
|
|
||||||
cF("fWereWolfShortBlade", 1); // 0
|
|
||||||
cF("fWereWolfAcrobatics", 150); // 80
|
|
||||||
cF("fWereWolfSpeechcraft", 1); // 0
|
|
||||||
cF("fWereWolfAlteration", 1); // 0
|
|
||||||
cF("fWereWolfIllusion", 1); // 0
|
|
||||||
cF("fWereWolfLongBlade", 1); // 0
|
|
||||||
cF("fWereWolfMarksman", 1); // 0
|
|
||||||
cF("fWereWolfHandtoHand", 100); // same
|
|
||||||
cF("fWereWolfIntellegence", 1); // 0
|
|
||||||
cF("fWereWolfAlchemy", 1); // 0
|
|
||||||
cF("fWereWolfUnarmored", 100); // same
|
|
||||||
cF("fWereWolfAxe", 1); // 0
|
|
||||||
cF("fWereWolfRunMult", 1.5); // 1.3
|
|
||||||
cF("fWereWolfMagicka", 100); // same
|
|
||||||
cF("fWereWolfAgility", 150); // same
|
|
||||||
cF("fWereWolfBluntWeapon", 1); // 0
|
|
||||||
cF("fWereWolfSecurity", 1); // 0
|
|
||||||
cF("fWereWolfPersonality", 1); // 0
|
|
||||||
cF("fWereWolfMerchantile", 1); // 0
|
|
||||||
cF("fWereWolfHeavyArmor", 1); // 0
|
|
||||||
cF("fWereWolfSpear", 1); // 0
|
|
||||||
cF("fWereWolfStrength", 150); // same
|
|
||||||
cF("fWereWolfHealth", 2); // same
|
|
||||||
cF("fWereWolfMysticism", 1); // 0
|
|
||||||
cF("fWereWolfLightArmor", 1); // 0
|
|
||||||
cF("fWereWolfWillPower", 1); // 0
|
|
||||||
cF("fWereWolfSpeed", 150); // 90
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef cI
|
/*
|
||||||
#undef cF
|
Checks for dirty tribunal values. These will be ignored if found
|
||||||
#undef cS
|
in any file except when they are found in "Tribunal.esm".
|
||||||
|
*/
|
||||||
|
bool isDirtyTribunal();
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
// Bloodmoon variant
|
||||||
{
|
bool isDirtyBloodmoon();
|
||||||
assert(id != "");
|
|
||||||
|
|
||||||
dirty = false;
|
void load(ESMReader &esm);
|
||||||
|
|
||||||
// We are apparently allowed to be empty
|
|
||||||
if(!esm.hasMoreSubs())
|
|
||||||
{
|
|
||||||
type = VT_None;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load some data
|
|
||||||
esm.getSubName();
|
|
||||||
NAME n = esm.retSubName();
|
|
||||||
if(n == "STRV")
|
|
||||||
{
|
|
||||||
str = esm.getHString();
|
|
||||||
type = VT_String;
|
|
||||||
}
|
|
||||||
else if(n == "INTV")
|
|
||||||
{
|
|
||||||
esm.getHT(i);
|
|
||||||
type = VT_Int;
|
|
||||||
}
|
|
||||||
else if(n == "FLTV")
|
|
||||||
{
|
|
||||||
esm.getHT(f);
|
|
||||||
type = VT_Float;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
esm.fail("Unwanted subrecord type");
|
|
||||||
|
|
||||||
int spf = esm.getSpecial();
|
|
||||||
|
|
||||||
// Check if this is one of the dirty values mentioned above. If it
|
|
||||||
// is, we set the dirty flag. This will ONLY work if you've set
|
|
||||||
// the 'id' string correctly before calling load().
|
|
||||||
|
|
||||||
if( ( spf != SF_Tribunal && isDirtyTribunal() ) ||
|
|
||||||
( spf != SF_Bloodmoon && isDirtyBloodmoon() ) )
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
133
components/esm/loadinfo.cpp
Normal file
133
components/esm/loadinfo.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#include "loadinfo.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void DialInfo::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
id = esm.getHNString("INAM");
|
||||||
|
prev = esm.getHNString("PNAM");
|
||||||
|
next = esm.getHNString("NNAM");
|
||||||
|
|
||||||
|
// Not present if deleted
|
||||||
|
if (esm.isNextSub("DATA"))
|
||||||
|
esm.getHT(data, 12);
|
||||||
|
|
||||||
|
// What follows is somewhat spaghetti-ish, but it's worth if for
|
||||||
|
// an extra speedup. INFO is by far the most common record type.
|
||||||
|
|
||||||
|
// subName is a reference to the original, so it changes whenever
|
||||||
|
// a new sub name is read. esm.isEmptyOrGetName() will get the
|
||||||
|
// next name for us, or return true if there are no more records.
|
||||||
|
esm.getSubName();
|
||||||
|
const NAME &subName = esm.retSubName();
|
||||||
|
|
||||||
|
if (subName.val == REC_ONAM)
|
||||||
|
{
|
||||||
|
actor = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subName.val == REC_RNAM)
|
||||||
|
{
|
||||||
|
race = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subName.val == REC_CNAM)
|
||||||
|
{
|
||||||
|
clas = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
factionLess = false;
|
||||||
|
if (subName.val == REC_FNAM)
|
||||||
|
{
|
||||||
|
npcFaction = esm.getHString();
|
||||||
|
if (npcFaction == "FFFF")
|
||||||
|
factionLess = true;
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subName.val == REC_ANAM)
|
||||||
|
{
|
||||||
|
cell = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subName.val == REC_DNAM)
|
||||||
|
{
|
||||||
|
pcFaction = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subName.val == REC_SNAM)
|
||||||
|
{
|
||||||
|
sound = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (subName.val == REC_NAME)
|
||||||
|
{
|
||||||
|
response = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (subName.val == REC_SCVR)
|
||||||
|
{
|
||||||
|
SelectStruct ss;
|
||||||
|
|
||||||
|
ss.selectRule = esm.getHString();
|
||||||
|
esm.isEmptyOrGetName();
|
||||||
|
|
||||||
|
if (subName.val == REC_INTV)
|
||||||
|
{
|
||||||
|
ss.type = VT_Int;
|
||||||
|
esm.getHT(ss.i);
|
||||||
|
}
|
||||||
|
else if (subName.val == REC_FLTV)
|
||||||
|
{
|
||||||
|
ss.type = VT_Float;
|
||||||
|
esm.getHT(ss.f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esm.fail(
|
||||||
|
"INFO.SCVR must precede INTV or FLTV, not "
|
||||||
|
+ subName.toString());
|
||||||
|
|
||||||
|
selects.push_back(ss);
|
||||||
|
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subName.val == REC_BNAM)
|
||||||
|
{
|
||||||
|
resultScript = esm.getHString();
|
||||||
|
if (esm.isEmptyOrGetName())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
questStatus = QS_None;
|
||||||
|
|
||||||
|
if (subName.val == REC_QSTN)
|
||||||
|
questStatus = QS_Name;
|
||||||
|
else if (subName.val == REC_QSTF)
|
||||||
|
questStatus = QS_Finished;
|
||||||
|
else if (subName.val == REC_QSTR)
|
||||||
|
questStatus = QS_Restart;
|
||||||
|
else if (subName.val == REC_DELE)
|
||||||
|
questStatus = QS_Deleted;
|
||||||
|
else
|
||||||
|
esm.fail(
|
||||||
|
"Don't know what to do with " + subName.toString()
|
||||||
|
+ " in INFO " + id);
|
||||||
|
|
||||||
|
if (questStatus != QS_None)
|
||||||
|
// Skip rest of record
|
||||||
|
esm.skipRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
// NOT DONE
|
// NOT DONE
|
||||||
|
|
||||||
|
@ -15,88 +16,88 @@ namespace ESM {
|
||||||
|
|
||||||
struct DialInfo
|
struct DialInfo
|
||||||
{
|
{
|
||||||
enum Gender
|
enum Gender
|
||||||
{
|
{
|
||||||
Male = 0,
|
Male = 0,
|
||||||
Female = 1,
|
Female = 1,
|
||||||
NA = -1
|
NA = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DATAstruct
|
struct DATAstruct
|
||||||
{
|
|
||||||
int unknown1;
|
|
||||||
int disposition;
|
|
||||||
char rank; // Rank of NPC
|
|
||||||
char gender; // See Gender enum
|
|
||||||
char PCrank; // Player rank
|
|
||||||
char unknown2;
|
|
||||||
}; // 12 bytes
|
|
||||||
DATAstruct data;
|
|
||||||
|
|
||||||
// The rules for whether or not we will select this dialog item.
|
|
||||||
struct SelectStruct
|
|
||||||
{
|
|
||||||
std::string selectRule; // This has a complicated format
|
|
||||||
float f; // Only one of 'f' or 'i' is used
|
|
||||||
int i;
|
|
||||||
VarType type;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Journal quest indices (introduced with the quest system in Tribunal)
|
|
||||||
enum QuestStatus
|
|
||||||
{
|
{
|
||||||
QS_None,
|
int unknown1;
|
||||||
QS_Name,
|
int disposition;
|
||||||
QS_Finished,
|
char rank; // Rank of NPC
|
||||||
QS_Restart,
|
char gender; // See Gender enum
|
||||||
QS_Deleted
|
char PCrank; // Player rank
|
||||||
|
char unknown2;
|
||||||
|
}; // 12 bytes
|
||||||
|
DATAstruct data;
|
||||||
|
|
||||||
|
// The rules for whether or not we will select this dialog item.
|
||||||
|
struct SelectStruct
|
||||||
|
{
|
||||||
|
std::string selectRule; // This has a complicated format
|
||||||
|
float f; // Only one of 'f' or 'i' is used
|
||||||
|
int i;
|
||||||
|
VarType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rules for when to include this item in the final list of options
|
// Journal quest indices (introduced with the quest system in Tribunal)
|
||||||
// visible to the player.
|
enum QuestStatus
|
||||||
std::vector<SelectStruct> selects;
|
|
||||||
|
|
||||||
// Id of this, previous and next INFO items
|
|
||||||
std::string id, prev, next,
|
|
||||||
|
|
||||||
// Various references used in determining when to select this item.
|
|
||||||
actor, race, clas, npcFaction, pcFaction, cell,
|
|
||||||
|
|
||||||
// Sound and text associated with this item
|
|
||||||
sound, response,
|
|
||||||
|
|
||||||
// Result script (uncomiled) to run whenever this dialog item is
|
|
||||||
// selected
|
|
||||||
resultScript;
|
|
||||||
|
|
||||||
// ONLY include this item the NPC is not part of any faction.
|
|
||||||
bool factionLess;
|
|
||||||
|
|
||||||
// Status of this quest item
|
|
||||||
QuestStatus questStatus;
|
|
||||||
|
|
||||||
// Hexadecimal versions of the various subrecord names.
|
|
||||||
enum SubNames
|
|
||||||
{
|
{
|
||||||
REC_ONAM = 0x4d414e4f,
|
QS_None,
|
||||||
REC_RNAM = 0x4d414e52,
|
QS_Name,
|
||||||
REC_CNAM = 0x4d414e43,
|
QS_Finished,
|
||||||
REC_FNAM = 0x4d414e46,
|
QS_Restart,
|
||||||
REC_ANAM = 0x4d414e41,
|
QS_Deleted
|
||||||
REC_DNAM = 0x4d414e44,
|
|
||||||
REC_SNAM = 0x4d414e53,
|
|
||||||
REC_NAME = 0x454d414e,
|
|
||||||
REC_SCVR = 0x52564353,
|
|
||||||
REC_INTV = 0x56544e49,
|
|
||||||
REC_FLTV = 0x56544c46,
|
|
||||||
REC_BNAM = 0x4d414e42,
|
|
||||||
REC_QSTN = 0x4e545351,
|
|
||||||
REC_QSTF = 0x46545351,
|
|
||||||
REC_QSTR = 0x52545351,
|
|
||||||
REC_DELE = 0x454c4544
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
// Rules for when to include this item in the final list of options
|
||||||
|
// visible to the player.
|
||||||
|
std::vector<SelectStruct> selects;
|
||||||
|
|
||||||
|
// Id of this, previous and next INFO items
|
||||||
|
std::string id, prev, next,
|
||||||
|
|
||||||
|
// Various references used in determining when to select this item.
|
||||||
|
actor, race, clas, npcFaction, pcFaction, cell,
|
||||||
|
|
||||||
|
// Sound and text associated with this item
|
||||||
|
sound, response,
|
||||||
|
|
||||||
|
// Result script (uncomiled) to run whenever this dialog item is
|
||||||
|
// selected
|
||||||
|
resultScript;
|
||||||
|
|
||||||
|
// ONLY include this item the NPC is not part of any faction.
|
||||||
|
bool factionLess;
|
||||||
|
|
||||||
|
// Status of this quest item
|
||||||
|
QuestStatus questStatus;
|
||||||
|
|
||||||
|
// Hexadecimal versions of the various subrecord names.
|
||||||
|
enum SubNames
|
||||||
|
{
|
||||||
|
REC_ONAM = 0x4d414e4f,
|
||||||
|
REC_RNAM = 0x4d414e52,
|
||||||
|
REC_CNAM = 0x4d414e43,
|
||||||
|
REC_FNAM = 0x4d414e46,
|
||||||
|
REC_ANAM = 0x4d414e41,
|
||||||
|
REC_DNAM = 0x4d414e44,
|
||||||
|
REC_SNAM = 0x4d414e53,
|
||||||
|
REC_NAME = 0x454d414e,
|
||||||
|
REC_SCVR = 0x52564353,
|
||||||
|
REC_INTV = 0x56544e49,
|
||||||
|
REC_FLTV = 0x56544c46,
|
||||||
|
REC_BNAM = 0x4d414e42,
|
||||||
|
REC_QSTN = 0x4e545351,
|
||||||
|
REC_QSTF = 0x46545351,
|
||||||
|
REC_QSTR = 0x52545351,
|
||||||
|
REC_DELE = 0x454c4544
|
||||||
|
};
|
||||||
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
15
components/esm/loadingr.cpp
Normal file
15
components/esm/loadingr.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "loadingr.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Ingredient::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
esm.getHNT(data, "IRDT", 56);
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alchemy ingredient
|
* Alchemy ingredient
|
||||||
|
@ -11,26 +12,19 @@ namespace ESM {
|
||||||
|
|
||||||
struct Ingredient
|
struct Ingredient
|
||||||
{
|
{
|
||||||
struct IRDTstruct
|
struct IRDTstruct
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
int effectID[4]; // Effect, 0 or -1 means none
|
int effectID[4]; // Effect, 0 or -1 means none
|
||||||
int skills[4]; // SkillEnum related to effect
|
int skills[4]; // SkillEnum related to effect
|
||||||
int attributes[4]; // Attribute related to effect
|
int attributes[4]; // Attribute related to effect
|
||||||
};
|
};
|
||||||
|
|
||||||
IRDTstruct data;
|
IRDTstruct data;
|
||||||
std::string name, model, icon, script;
|
std::string name, model, icon, script;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
esm.getHNT(data, "IRDT", 56);
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
32
components/esm/loadland.cpp
Normal file
32
components/esm/loadland.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "loadland.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
void Land::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
// Get the grid location
|
||||||
|
esm.getSubNameIs("INTV");
|
||||||
|
esm.getSubHeaderIs(8);
|
||||||
|
esm.getT<int>(X);
|
||||||
|
esm.getT<int>(Y);
|
||||||
|
|
||||||
|
esm.getHNT(flags, "DATA");
|
||||||
|
|
||||||
|
// Store the file position
|
||||||
|
context = esm.getContext();
|
||||||
|
|
||||||
|
hasData = false;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
// Skip these here. Load the actual data when the cell is loaded.
|
||||||
|
if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;}
|
||||||
|
if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;}
|
||||||
|
if(esm.isNextSub("WNAM")) esm.skipHSubSize(81);
|
||||||
|
if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675);
|
||||||
|
if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;}
|
||||||
|
|
||||||
|
// We need all three of VNML, VHGT and VTEX in order to use the
|
||||||
|
// landscape.
|
||||||
|
hasData = (cnt == 3);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,51 +3,25 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Landscape data.
|
* Landscape data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Land
|
struct Land
|
||||||
{
|
{
|
||||||
int flags; // Only first four bits seem to be used, don't know what
|
int flags; // Only first four bits seem to be used, don't know what
|
||||||
// they mean.
|
// they mean.
|
||||||
int X, Y; // Map coordinates.
|
int X, Y; // Map coordinates.
|
||||||
|
|
||||||
// File context. This allows the ESM reader to be 'reset' to this
|
// File context. This allows the ESM reader to be 'reset' to this
|
||||||
// location later when we are ready to load the full data set.
|
// location later when we are ready to load the full data set.
|
||||||
ESM_Context context;
|
ESM_Context context;
|
||||||
|
|
||||||
bool hasData;
|
bool hasData;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
// Get the grid location
|
|
||||||
esm.getSubNameIs("INTV");
|
|
||||||
esm.getSubHeaderIs(8);
|
|
||||||
esm.getT<int>(X);
|
|
||||||
esm.getT<int>(Y);
|
|
||||||
|
|
||||||
esm.getHNT(flags, "DATA");
|
|
||||||
|
|
||||||
// Store the file position
|
|
||||||
context = esm.getContext();
|
|
||||||
|
|
||||||
hasData = false;
|
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
// Skip these here. Load the actual data when the cell is loaded.
|
|
||||||
if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;}
|
|
||||||
if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;}
|
|
||||||
if(esm.isNextSub("WNAM")) esm.skipHSubSize(81);
|
|
||||||
if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675);
|
|
||||||
if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;}
|
|
||||||
|
|
||||||
// We need all three of VNML, VHGT and VTEX in order to use the
|
|
||||||
// landscape.
|
|
||||||
hasData = (cnt == 3);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
34
components/esm/loadlevlist.cpp
Normal file
34
components/esm/loadlevlist.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "loadlevlist.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void LeveledListBase::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(flags, "DATA");
|
||||||
|
esm.getHNT(chanceNone, "NNAM");
|
||||||
|
|
||||||
|
if (esm.isNextSub("INDX"))
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
esm.getHT(len);
|
||||||
|
list.resize(len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: Merge with an existing lists here. This can be done
|
||||||
|
// simply by adding the lists together, making sure that they are
|
||||||
|
// sorted by level. A better way might be to exclude repeated
|
||||||
|
// items. Also, some times we don't want to merge lists, just
|
||||||
|
// overwrite. Figure out a way to give the user this option.
|
||||||
|
|
||||||
|
for (size_t i = 0; i < list.size(); i++)
|
||||||
|
{
|
||||||
|
LevelItem &li = list[i];
|
||||||
|
li.id = esm.getHNString(recName);
|
||||||
|
esm.getHNT(li.level, "INTV");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Leveled lists. Since these have identical layout, I only bothered
|
* Leveled lists. Since these have identical layout, I only bothered
|
||||||
|
@ -15,65 +16,50 @@ namespace ESM {
|
||||||
|
|
||||||
struct LeveledListBase
|
struct LeveledListBase
|
||||||
{
|
{
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
AllLevels = 0x01, // Calculate from all levels <= player
|
AllLevels = 0x01, // Calculate from all levels <= player
|
||||||
// level, not just the closest below
|
// level, not just the closest below
|
||||||
// player.
|
// player.
|
||||||
Each = 0x02 // Select a new item each time this
|
Each = 0x02 // Select a new item each time this
|
||||||
// list is instantiated, instead of
|
// list is instantiated, instead of
|
||||||
// giving several identical items
|
// giving several identical items
|
||||||
}; // (used when a container has more
|
}; // (used when a container has more
|
||||||
// than one instance of one leveled
|
// than one instance of one leveled
|
||||||
// list.)
|
// list.)
|
||||||
int flags;
|
int flags;
|
||||||
unsigned char chanceNone; // Chance that none are selected (0-255?)
|
unsigned char chanceNone; // Chance that none are selected (0-255?)
|
||||||
|
|
||||||
// Record name used to read references. Must be set before load() is
|
// Record name used to read references. Must be set before load() is
|
||||||
// called.
|
// called.
|
||||||
const char *recName;
|
const char *recName;
|
||||||
|
|
||||||
struct LevelItem
|
struct LevelItem
|
||||||
{
|
{
|
||||||
std::string id;
|
std::string id;
|
||||||
short level;
|
short level;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<LevelItem> list;
|
std::vector<LevelItem> list;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(flags, "DATA");
|
|
||||||
esm.getHNT(chanceNone, "NNAM");
|
|
||||||
|
|
||||||
if(esm.isNextSub("INDX"))
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
esm.getHT(len);
|
|
||||||
list.resize(len);
|
|
||||||
}
|
|
||||||
else return;
|
|
||||||
|
|
||||||
// TODO: Merge with an existing lists here. This can be done
|
|
||||||
// simply by adding the lists together, making sure that they are
|
|
||||||
// sorted by level. A better way might be to exclude repeated
|
|
||||||
// items. Also, some times we don't want to merge lists, just
|
|
||||||
// overwrite. Figure out a way to give the user this option.
|
|
||||||
|
|
||||||
for(size_t i=0; i<list.size(); i++)
|
|
||||||
{
|
|
||||||
LevelItem &li = list[i];
|
|
||||||
li.id = esm.getHNString(recName);
|
|
||||||
esm.getHNT(li.level, "INTV");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreatureLevList : LeveledListBase
|
struct CreatureLevList: LeveledListBase
|
||||||
{ CreatureLevList() { recName = "CNAM"; } };
|
{
|
||||||
|
CreatureLevList()
|
||||||
|
{
|
||||||
|
recName = "CNAM";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct ItemLevList : LeveledListBase
|
struct ItemLevList: LeveledListBase
|
||||||
{ ItemLevList() { recName = "INAM"; } };
|
{
|
||||||
|
ItemLevList()
|
||||||
|
{
|
||||||
|
recName = "INAM";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
17
components/esm/loadligh.cpp
Normal file
17
components/esm/loadligh.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include "loadligh.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Light::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
assert(sizeof(data) == 24);
|
||||||
|
esm.getHNT(data, "LHDT", 24);
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
sound = esm.getHNOString("SNAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lights. Includes static light sources and also carryable candles
|
* Lights. Includes static light sources and also carryable candles
|
||||||
|
@ -12,43 +13,34 @@ namespace ESM {
|
||||||
|
|
||||||
struct Light
|
struct Light
|
||||||
{
|
{
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
Dynamic = 0x001,
|
Dynamic = 0x001,
|
||||||
Carry = 0x002, // Can be carried
|
Carry = 0x002, // Can be carried
|
||||||
Negative = 0x004, // Negative light?
|
Negative = 0x004, // Negative light?
|
||||||
Flicker = 0x008,
|
Flicker = 0x008,
|
||||||
Fire = 0x010,
|
Fire = 0x010,
|
||||||
OffDefault = 0x020, // Off by default
|
OffDefault = 0x020, // Off by default
|
||||||
FlickerSlow = 0x040,
|
FlickerSlow = 0x040,
|
||||||
Pulse = 0x080,
|
Pulse = 0x080,
|
||||||
PulseSlow = 0x100
|
PulseSlow = 0x100
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LHDTstruct
|
struct LHDTstruct
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
int time; // Duration
|
int time; // Duration
|
||||||
int radius;
|
int radius;
|
||||||
int color; // 4-byte rgba value
|
int color; // 4-byte rgba value
|
||||||
int flags;
|
int flags;
|
||||||
}; // Size = 24 bytes
|
}; // Size = 24 bytes
|
||||||
|
|
||||||
LHDTstruct data;
|
LHDTstruct data;
|
||||||
|
|
||||||
std::string sound, script, model, icon, name;
|
std::string sound, script, model, icon, name;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
assert(sizeof(data) == 24);
|
|
||||||
esm.getHNT(data, "LHDT", 24);
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
sound = esm.getHNOString("SNAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
30
components/esm/loadlocks.cpp
Normal file
30
components/esm/loadlocks.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include "loadlocks.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Tool::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
|
||||||
|
esm.getSubName();
|
||||||
|
NAME n = esm.retSubName();
|
||||||
|
// The data name varies, RIDT for repair items, LKDT for lock
|
||||||
|
// picks, PBDT for probes
|
||||||
|
|
||||||
|
esm.getHT(data, 16);
|
||||||
|
|
||||||
|
if (n == "RIDT")
|
||||||
|
{
|
||||||
|
// Swap t.data.quality and t.data.uses for repair items (sigh)
|
||||||
|
float tmp = *((float*) &data.uses);
|
||||||
|
data.uses = *((int*) &data.quality);
|
||||||
|
data.quality = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file covers lockpicks (LOCK), probes (PROB) and armor repair
|
* This file covers lockpicks (LOCK), probes (PROB) and armor repair
|
||||||
|
@ -12,51 +13,29 @@ namespace ESM {
|
||||||
|
|
||||||
struct Tool
|
struct Tool
|
||||||
{
|
{
|
||||||
struct Data
|
struct Data
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
float quality; // And when I say nearly identical structure, I
|
float quality; // And when I say nearly identical structure, I
|
||||||
int uses; // mean perfectly identical except that these two
|
int uses; // mean perfectly identical except that these two
|
||||||
// variables are swaped for repair items. Don't ask
|
// variables are swaped for repair items. Don't ask
|
||||||
// me why.
|
// me why.
|
||||||
}; // Size = 16
|
}; // Size = 16
|
||||||
|
|
||||||
Data data;
|
Data data;
|
||||||
std::string name, model, icon, script;
|
std::string name, model, icon, script;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
|
|
||||||
esm.getSubName();
|
|
||||||
NAME n = esm.retSubName();
|
|
||||||
// The data name varies, RIDT for repair items, LKDT for lock
|
|
||||||
// picks, PBDT for probes
|
|
||||||
|
|
||||||
esm.getHT(data, 16);
|
|
||||||
|
|
||||||
if(n == "RIDT")
|
|
||||||
{
|
|
||||||
// Swap t.data.quality and t.data.uses for repair items (sigh)
|
|
||||||
float tmp = *((float*)&data.uses);
|
|
||||||
data.uses = *((int*)&data.quality);
|
|
||||||
data.quality = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Probe : Tool
|
struct Probe: Tool
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Repair : Tool
|
struct Repair: Tool
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
12
components/esm/loadltex.cpp
Normal file
12
components/esm/loadltex.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "loadltex.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void LandTexture::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(index, "INTV");
|
||||||
|
texture = esm.getHNString("DATA");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Texture used for texturing landscape.
|
* Texture used for texturing landscape.
|
||||||
|
@ -23,14 +24,10 @@ namespace ESM {
|
||||||
|
|
||||||
struct LandTexture
|
struct LandTexture
|
||||||
{
|
{
|
||||||
std::string id, texture;
|
std::string id, texture;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(index, "INTV");
|
|
||||||
texture = esm.getHNString("DATA");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
27
components/esm/loadmgef.cpp
Normal file
27
components/esm/loadmgef.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "loadmgef.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void MagicEffect::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(index, "INDX");
|
||||||
|
|
||||||
|
esm.getHNT(data, "MEDT", 36);
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
particle = esm.getHNOString("PTEX");
|
||||||
|
|
||||||
|
boltSound = esm.getHNOString("BSND");
|
||||||
|
castSound = esm.getHNOString("CSND");
|
||||||
|
hitSound = esm.getHNOString("HSND");
|
||||||
|
areaSound = esm.getHNOString("ASND");
|
||||||
|
|
||||||
|
casting = esm.getHNOString("CVFX");
|
||||||
|
bolt = esm.getHNOString("BVFX");
|
||||||
|
hit = esm.getHNOString("HVFX");
|
||||||
|
area = esm.getHNOString("AVFX");
|
||||||
|
|
||||||
|
description = esm.getHNOString("DESC");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,68 +3,49 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct MagicEffect
|
struct MagicEffect
|
||||||
{
|
{
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
SpellMaking = 0x0200,
|
SpellMaking = 0x0200,
|
||||||
Enchanting = 0x0400,
|
Enchanting = 0x0400,
|
||||||
Negative = 0x0800 // A harmful effect. Will determine whether
|
Negative = 0x0800 // A harmful effect. Will determine whether
|
||||||
// eg. NPCs regard this spell as an attack.
|
// eg. NPCs regard this spell as an attack.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MEDTstruct
|
struct MEDTstruct
|
||||||
{
|
{
|
||||||
int school; // SpellSchool, see defs.hpp
|
int school; // SpellSchool, see defs.hpp
|
||||||
float baseCost;
|
float baseCost;
|
||||||
int flags;
|
int flags;
|
||||||
// Properties of the fired magic 'ball' I think
|
// Properties of the fired magic 'ball' I think
|
||||||
int red, blue, green;
|
int red, blue, green;
|
||||||
float speed, size, sizeCap;
|
float speed, size, sizeCap;
|
||||||
}; // 36 bytes
|
}; // 36 bytes
|
||||||
|
|
||||||
MEDTstruct data;
|
MEDTstruct data;
|
||||||
|
|
||||||
std::string icon, particle, // Textures
|
std::string icon, particle, // Textures
|
||||||
casting, hit, area, // Statics
|
casting, hit, area, // Statics
|
||||||
bolt, // Weapon
|
bolt, // Weapon
|
||||||
castSound, boltSound,
|
castSound, boltSound, hitSound, areaSound, // Sounds
|
||||||
hitSound, areaSound, // Sounds
|
description;
|
||||||
description;
|
|
||||||
|
|
||||||
// Index of this magical effect. Corresponds to one of the
|
// Index of this magical effect. Corresponds to one of the
|
||||||
// hard-coded effects in the original engine:
|
// hard-coded effects in the original engine:
|
||||||
// 0-136 in Morrowind
|
// 0-136 in Morrowind
|
||||||
// 137 in Tribunal
|
// 137 in Tribunal
|
||||||
// 138-140 in Bloodmoon (also changes 64?)
|
// 138-140 in Bloodmoon (also changes 64?)
|
||||||
// 141-142 are summon effects introduced in bloodmoon, but not used
|
// 141-142 are summon effects introduced in bloodmoon, but not used
|
||||||
// there. They can be redefined in mods by setting the name in GMST
|
// there. They can be redefined in mods by setting the name in GMST
|
||||||
// sEffectSummonCreature04/05 creature id in
|
// sEffectSummonCreature04/05 creature id in
|
||||||
// sMagicCreature04ID/05ID.
|
// sMagicCreature04ID/05ID.
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(index, "INDX");
|
|
||||||
|
|
||||||
esm.getHNT(data, "MEDT", 36);
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
particle = esm.getHNOString("PTEX");
|
|
||||||
|
|
||||||
boltSound = esm.getHNOString("BSND");
|
|
||||||
castSound = esm.getHNOString("CSND");
|
|
||||||
hitSound = esm.getHNOString("HSND");
|
|
||||||
areaSound = esm.getHNOString("ASND");
|
|
||||||
|
|
||||||
casting = esm.getHNOString("CVFX");
|
|
||||||
bolt = esm.getHNOString("BVFX");
|
|
||||||
hit = esm.getHNOString("HVFX");
|
|
||||||
area = esm.getHNOString("AVFX");
|
|
||||||
|
|
||||||
description = esm.getHNOString("DESC");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
15
components/esm/loadmisc.cpp
Normal file
15
components/esm/loadmisc.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "loadmisc.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Misc::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(data, "MCDT", 12);
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Misc inventory items, basically things that have no use but can be
|
* Misc inventory items, basically things that have no use but can be
|
||||||
|
@ -12,26 +13,19 @@ namespace ESM {
|
||||||
|
|
||||||
struct Misc
|
struct Misc
|
||||||
{
|
{
|
||||||
struct MCDTstruct
|
struct MCDTstruct
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
int isKey; // There are many keys in Morrowind.esm that has this
|
int isKey; // There are many keys in Morrowind.esm that has this
|
||||||
// set to 0. TODO: Check what this field corresponds to
|
// set to 0. TODO: Check what this field corresponds to
|
||||||
// in the editor.
|
// in the editor.
|
||||||
};
|
};
|
||||||
MCDTstruct data;
|
MCDTstruct data;
|
||||||
|
|
||||||
std::string name, model, icon, script;
|
std::string name, model, icon, script;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(data, "MCDT", 12);
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
48
components/esm/loadnpc.cpp
Normal file
48
components/esm/loadnpc.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include "loadnpc.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void NPC::load(ESMReader &esm, const std::string& id)
|
||||||
|
{
|
||||||
|
mId = id;
|
||||||
|
|
||||||
|
npdt52.gold = -10;
|
||||||
|
|
||||||
|
model = esm.getHNOString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
|
||||||
|
race = esm.getHNString("RNAM");
|
||||||
|
cls = esm.getHNString("CNAM");
|
||||||
|
faction = esm.getHNString("ANAM");
|
||||||
|
head = esm.getHNString("BNAM");
|
||||||
|
hair = esm.getHNString("KNAM");
|
||||||
|
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
|
||||||
|
esm.getSubNameIs("NPDT");
|
||||||
|
esm.getSubHeader();
|
||||||
|
if (esm.getSubSize() == 52)
|
||||||
|
esm.getExact(&npdt52, 52);
|
||||||
|
else if (esm.getSubSize() == 12)
|
||||||
|
esm.getExact(&npdt12, 12);
|
||||||
|
else
|
||||||
|
esm.fail("NPC_NPDT must be 12 or 52 bytes long");
|
||||||
|
|
||||||
|
esm.getHNT(flags, "FLAG");
|
||||||
|
|
||||||
|
inventory.load(esm);
|
||||||
|
spells.load(esm);
|
||||||
|
|
||||||
|
if (esm.isNextSub("AIDT"))
|
||||||
|
{
|
||||||
|
esm.getHExact(&AI, sizeof(AI));
|
||||||
|
hasAI = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hasAI = false;
|
||||||
|
|
||||||
|
esm.skipRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
components/esm/loadpgrd.cpp
Normal file
35
components/esm/loadpgrd.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "loadpgrd.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void PathGrid::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(data, "DATA", 12);
|
||||||
|
cell = esm.getHNString("NAME");
|
||||||
|
|
||||||
|
// Remember this file position
|
||||||
|
context = esm.getContext();
|
||||||
|
|
||||||
|
// Check that the sizes match up. Size = 16 * s2 (path points?)
|
||||||
|
if (esm.isNextSub("PGRP"))
|
||||||
|
{
|
||||||
|
esm.skipHSub();
|
||||||
|
int size = esm.getSubSize();
|
||||||
|
if (size != 16 * data.s2)
|
||||||
|
esm.fail("Path grid table size mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size varies. Path grid chances? Connections? Multiples of 4
|
||||||
|
// suggest either int or two shorts, or perhaps a float. Study
|
||||||
|
// it later.
|
||||||
|
if (esm.isNextSub("PGRC"))
|
||||||
|
{
|
||||||
|
esm.skipHSub();
|
||||||
|
int size = esm.getSubSize();
|
||||||
|
if (size % 4 != 0)
|
||||||
|
esm.fail("PGRC size not a multiple of 4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,54 +3,28 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Path grid.
|
* Path grid.
|
||||||
*/
|
*/
|
||||||
struct PathGrid
|
struct PathGrid
|
||||||
{
|
{
|
||||||
struct DATAstruct
|
struct DATAstruct
|
||||||
{
|
{
|
||||||
int x, y; // Grid location, matches cell for exterior cells
|
int x, y; // Grid location, matches cell for exterior cells
|
||||||
short s1; // ?? Usually but not always a power of 2. Doesn't seem
|
short s1; // ?? Usually but not always a power of 2. Doesn't seem
|
||||||
// to have any relation to the size of PGRC.
|
// to have any relation to the size of PGRC.
|
||||||
short s2; // Number of path points? Size of PGRP block is always 16 * s2;
|
short s2; // Number of path points? Size of PGRP block is always 16 * s2;
|
||||||
}; // 12 bytes
|
}; // 12 bytes
|
||||||
|
|
||||||
std::string cell; // Cell name
|
std::string cell; // Cell name
|
||||||
DATAstruct data;
|
DATAstruct data;
|
||||||
ESM_Context context; // Context so we can return here later and
|
ESM_Context context; // Context so we can return here later and
|
||||||
// finish the job
|
// finish the job
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(data, "DATA", 12);
|
|
||||||
cell = esm.getHNString("NAME");
|
|
||||||
|
|
||||||
// Remember this file position
|
|
||||||
context = esm.getContext();
|
|
||||||
|
|
||||||
// Check that the sizes match up. Size = 16 * s2 (path points?)
|
|
||||||
if(esm.isNextSub("PGRP"))
|
|
||||||
{
|
|
||||||
esm.skipHSub();
|
|
||||||
int size = esm.getSubSize();
|
|
||||||
if(size != 16*data.s2)
|
|
||||||
esm.fail("Path grid table size mismatch");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size varies. Path grid chances? Connections? Multiples of 4
|
|
||||||
// suggest either int or two shorts, or perhaps a float. Study
|
|
||||||
// it later.
|
|
||||||
if(esm.isNextSub("PGRC"))
|
|
||||||
{
|
|
||||||
esm.skipHSub();
|
|
||||||
int size = esm.getSubSize();
|
|
||||||
if(size % 4 != 0)
|
|
||||||
esm.fail("PGRC size not a multiple of 4");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
14
components/esm/loadrace.cpp
Normal file
14
components/esm/loadrace.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "loadrace.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Race::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
esm.getHNT(data, "RADT", 140);
|
||||||
|
powers.load(esm);
|
||||||
|
description = esm.getHNOString("DESC");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,10 @@
|
||||||
#define _ESM_RACE_H
|
#define _ESM_RACE_H
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Race definition
|
* Race definition
|
||||||
|
@ -11,58 +13,51 @@ namespace ESM {
|
||||||
|
|
||||||
struct Race
|
struct Race
|
||||||
{
|
{
|
||||||
struct SkillBonus
|
struct SkillBonus
|
||||||
{
|
|
||||||
int skill; // SkillEnum
|
|
||||||
int bonus;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MaleFemale
|
|
||||||
{
|
|
||||||
int male, female;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MaleFemaleF
|
|
||||||
{
|
|
||||||
float male, female;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Flags
|
|
||||||
{
|
{
|
||||||
Playable = 0x01,
|
int skill; // SkillEnum
|
||||||
Beast = 0x02
|
int bonus;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RADTstruct
|
struct MaleFemale
|
||||||
{
|
{
|
||||||
// List of skills that get a bonus
|
int male, female;
|
||||||
SkillBonus bonus[7];
|
};
|
||||||
|
|
||||||
// Attribute values for male/female
|
struct MaleFemaleF
|
||||||
MaleFemale strength, intelligence, willpower, agility,
|
{
|
||||||
speed, endurance, personality, luck;
|
float male, female;
|
||||||
|
};
|
||||||
|
|
||||||
// The actual eye level height (in game units) is (probably) given
|
enum Flags
|
||||||
// as 'height' times 128. This has not been tested yet.
|
{
|
||||||
MaleFemaleF height, weight;
|
Playable = 0x01,
|
||||||
|
Beast = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
int flags; // 0x1 - playable, 0x2 - beast race
|
struct RADTstruct
|
||||||
|
{
|
||||||
|
// List of skills that get a bonus
|
||||||
|
SkillBonus bonus[7];
|
||||||
|
|
||||||
// Size = 140 bytes
|
// Attribute values for male/female
|
||||||
};
|
MaleFemale strength, intelligence, willpower, agility, speed,
|
||||||
|
endurance, personality, luck;
|
||||||
|
|
||||||
RADTstruct data;
|
// The actual eye level height (in game units) is (probably) given
|
||||||
|
// as 'height' times 128. This has not been tested yet.
|
||||||
|
MaleFemaleF height, weight;
|
||||||
|
|
||||||
std::string name, description;
|
int flags; // 0x1 - playable, 0x2 - beast race
|
||||||
SpellList powers;
|
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
}; // Size = 140 bytes
|
||||||
{
|
|
||||||
name = esm.getHNString("FNAM");
|
RADTstruct data;
|
||||||
esm.getHNT(data, "RADT", 140);
|
|
||||||
powers.load(esm);
|
std::string name, description;
|
||||||
description = esm.getHNOString("DESC");
|
SpellList powers;
|
||||||
}
|
|
||||||
|
void load(ESMReader &esm);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
29
components/esm/loadregn.cpp
Normal file
29
components/esm/loadregn.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "loadregn.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Region::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
name = esm.getHNString("FNAM");
|
||||||
|
|
||||||
|
if (esm.getVer() == VER_12)
|
||||||
|
esm.getHNExact(&data, sizeof(data) - 2, "WEAT");
|
||||||
|
else if (esm.getVer() == VER_13)
|
||||||
|
esm.getHNExact(&data, sizeof(data), "WEAT");
|
||||||
|
else
|
||||||
|
esm.fail("Don't know what to do in this version");
|
||||||
|
|
||||||
|
sleepList = esm.getHNOString("BNAM");
|
||||||
|
|
||||||
|
esm.getHNT(mapColor, "CNAM");
|
||||||
|
|
||||||
|
while (esm.hasMoreSubs())
|
||||||
|
{
|
||||||
|
SoundRef sr;
|
||||||
|
esm.getHNT(sr, "SNAM", 33);
|
||||||
|
soundList.push_back(sr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Region data
|
* Region data
|
||||||
|
@ -13,54 +14,33 @@ struct Region
|
||||||
{
|
{
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct WEATstruct
|
struct WEATstruct
|
||||||
{
|
{
|
||||||
// I guess these are probabilities
|
// I guess these are probabilities
|
||||||
char clear, cloudy, foggy, overcast, rain, thunder, ash,
|
char clear, cloudy, foggy, overcast, rain, thunder, ash, blight,
|
||||||
blight,
|
// Unknown weather, probably snow and something. Only
|
||||||
// Unknown weather, probably snow and something. Only
|
// present in file version 1.3.
|
||||||
// present in file version 1.3.
|
a, b;
|
||||||
a,b;
|
}; // 10 bytes
|
||||||
}; // 10 bytes
|
|
||||||
|
|
||||||
// Reference to a sound that is played randomly in this region
|
// Reference to a sound that is played randomly in this region
|
||||||
struct SoundRef
|
struct SoundRef
|
||||||
{
|
{
|
||||||
NAME32 sound;
|
NAME32 sound;
|
||||||
char chance;
|
char chance;
|
||||||
}; // 33 bytes
|
}; // 33 bytes
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
WEATstruct data;
|
WEATstruct data;
|
||||||
int mapColor; // RGBA
|
int mapColor; // RGBA
|
||||||
|
|
||||||
// sleepList refers to a eveled list of creatures you can meet if
|
// sleepList refers to a eveled list of creatures you can meet if
|
||||||
// you sleep outside in this region.
|
// you sleep outside in this region.
|
||||||
std::string name, sleepList;
|
std::string name, sleepList;
|
||||||
|
|
||||||
std::vector<SoundRef> soundList;
|
std::vector<SoundRef> soundList;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
name = esm.getHNString("FNAM");
|
|
||||||
|
|
||||||
if(esm.getVer() == VER_12)
|
|
||||||
esm.getHNExact(&data, sizeof(data)-2, "WEAT");
|
|
||||||
else if(esm.getVer() == VER_13)
|
|
||||||
esm.getHNExact(&data, sizeof(data), "WEAT");
|
|
||||||
else esm.fail("Don't know what to do in this version");
|
|
||||||
|
|
||||||
sleepList = esm.getHNOString("BNAM");
|
|
||||||
|
|
||||||
esm.getHNT(mapColor, "CNAM");
|
|
||||||
|
|
||||||
while(esm.hasMoreSubs())
|
|
||||||
{
|
|
||||||
SoundRef sr;
|
|
||||||
esm.getHNT(sr, "SNAM", 33);
|
|
||||||
soundList.push_back(sr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
42
components/esm/loadscpt.cpp
Normal file
42
components/esm/loadscpt.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "loadscpt.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Script::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(data, "SCHD", 52);
|
||||||
|
|
||||||
|
// List of local variables
|
||||||
|
if (esm.isNextSub("SCVR"))
|
||||||
|
{
|
||||||
|
int s = data.stringTableSize;
|
||||||
|
char* tmp = new char[s];
|
||||||
|
esm.getHExact(tmp, s);
|
||||||
|
|
||||||
|
// Set up the list of variable names
|
||||||
|
varNames.resize(data.numShorts + data.numLongs + data.numFloats);
|
||||||
|
|
||||||
|
// The tmp buffer is a null-byte separated string list, we
|
||||||
|
// just have to pick out one string at a time.
|
||||||
|
char* str = tmp;
|
||||||
|
for (size_t i = 0; i < varNames.size(); i++)
|
||||||
|
{
|
||||||
|
varNames[i] = std::string(str);
|
||||||
|
str += varNames[i].size() + 1;
|
||||||
|
|
||||||
|
if (str - tmp > s)
|
||||||
|
esm.fail("String table overflow");
|
||||||
|
}
|
||||||
|
delete[] tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Script data
|
||||||
|
scriptData.resize(data.scriptDataSize);
|
||||||
|
esm.getHNExact(&scriptData[0], scriptData.size(), "SCDT");
|
||||||
|
|
||||||
|
// Script text
|
||||||
|
scriptText = esm.getHNOString("SCTX");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Script definitions
|
* Script definitions
|
||||||
|
@ -12,80 +13,43 @@ namespace ESM {
|
||||||
class Script
|
class Script
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct SCHDstruct
|
struct SCHDstruct
|
||||||
{
|
{
|
||||||
/* Script name.
|
/* Script name.
|
||||||
|
|
||||||
NOTE: You should handle the name "Main" (case insensitive) with
|
NOTE: You should handle the name "Main" (case insensitive) with
|
||||||
care. With tribunal, modders got the ability to add 'start
|
care. With tribunal, modders got the ability to add 'start
|
||||||
scripts' to their mods, which is a script that is run at
|
scripts' to their mods, which is a script that is run at
|
||||||
startup and which runs throughout the game (I think.)
|
startup and which runs throughout the game (I think.)
|
||||||
|
|
||||||
However, before Tribunal, there was only one startup script,
|
However, before Tribunal, there was only one startup script,
|
||||||
called "Main". If mods wanted to make their own start scripts,
|
called "Main". If mods wanted to make their own start scripts,
|
||||||
they had to overwrite Main. This is obviously problem if
|
they had to overwrite Main. This is obviously problem if
|
||||||
multiple mods to this at the same time.
|
multiple mods to this at the same time.
|
||||||
|
|
||||||
Although most mods have switched to using Trib-style startup
|
Although most mods have switched to using Trib-style startup
|
||||||
scripts, some legacy mods might still overwrite Main, and this
|
scripts, some legacy mods might still overwrite Main, and this
|
||||||
can cause problems if several mods do it. I think the best
|
can cause problems if several mods do it. I think the best
|
||||||
course of action is to NEVER overwrite main, but instead add
|
course of action is to NEVER overwrite main, but instead add
|
||||||
each with a separate unique name and add them to the start
|
each with a separate unique name and add them to the start
|
||||||
script list. But there might be other problems with this
|
script list. But there might be other problems with this
|
||||||
approach though.
|
approach though.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NAME32 name;
|
NAME32 name;
|
||||||
|
|
||||||
// These describe the sizes we need to allocate for the script
|
// These describe the sizes we need to allocate for the script
|
||||||
// data.
|
// data.
|
||||||
int numShorts, numLongs, numFloats,
|
int numShorts, numLongs, numFloats, scriptDataSize, stringTableSize;
|
||||||
scriptDataSize, stringTableSize;
|
}; // 52 bytes
|
||||||
}; // 52 bytes
|
|
||||||
|
|
||||||
SCHDstruct data;
|
SCHDstruct data;
|
||||||
|
|
||||||
std::vector<std::string> varNames; // Variable names
|
std::vector<std::string> varNames; // Variable names
|
||||||
std::vector<char> scriptData; // Compiled bytecode
|
std::vector<char> scriptData; // Compiled bytecode
|
||||||
std::string scriptText; // Uncompiled script
|
std::string scriptText; // Uncompiled script
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(data, "SCHD", 52);
|
|
||||||
|
|
||||||
// List of local variables
|
|
||||||
if(esm.isNextSub("SCVR"))
|
|
||||||
{
|
|
||||||
int s = data.stringTableSize;
|
|
||||||
char* tmp = new char[s];
|
|
||||||
esm.getHExact(tmp, s);
|
|
||||||
|
|
||||||
// Set up the list of variable names
|
|
||||||
varNames.resize(data.numShorts +
|
|
||||||
data.numLongs +
|
|
||||||
data.numFloats);
|
|
||||||
|
|
||||||
// The tmp buffer is a null-byte separated string list, we
|
|
||||||
// just have to pick out one string at a time.
|
|
||||||
char* str = tmp;
|
|
||||||
for(size_t i=0; i< varNames.size(); i++)
|
|
||||||
{
|
|
||||||
varNames[i] = std::string(str);
|
|
||||||
str += varNames[i].size()+1;
|
|
||||||
|
|
||||||
if(str - tmp > s)
|
|
||||||
esm.fail("String table overflow");
|
|
||||||
}
|
|
||||||
delete[] tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Script data
|
|
||||||
scriptData.resize(data.scriptDataSize);
|
|
||||||
esm.getHNExact(&scriptData[0], scriptData.size(), "SCDT");
|
|
||||||
|
|
||||||
// Script text
|
|
||||||
scriptText = esm.getHNOString("SCTX");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,33 +1,70 @@
|
||||||
#include "loadskil.hpp"
|
#include "loadskil.hpp"
|
||||||
|
|
||||||
namespace ESMS
|
namespace ESM
|
||||||
{
|
{
|
||||||
const std::string Skill::sSkillNames[Length] = {
|
const std::string Skill::sSkillNameIds[Length] = {
|
||||||
"Block",
|
"sSkillBlock",
|
||||||
"Armorer",
|
"sSkillArmorer",
|
||||||
"Medium Armor",
|
"sSkillMediumarmor",
|
||||||
"Heavy Armor",
|
"sSkillHeavyarmor",
|
||||||
"Blunt Weapon",
|
"sSkillBluntweapon",
|
||||||
"Long Blade",
|
"sSkillLongblade",
|
||||||
"Axe",
|
"sSkillAxe",
|
||||||
"Spear",
|
"sSkillSpear",
|
||||||
"Athletics",
|
"sSkillAthletics",
|
||||||
"Enchant",
|
"sSkillEnchant",
|
||||||
"Destruction",
|
"sSkillDestruction",
|
||||||
"Alteration",
|
"sSkillAlteration",
|
||||||
"Illusion",
|
"sSkillIllusion",
|
||||||
"Conjuration",
|
"sSkillConjuration",
|
||||||
"Mysticism",
|
"sSkillMysticism",
|
||||||
"Restoration",
|
"sSkillRestoration",
|
||||||
"Alchemy",
|
"sSkillAlchemy",
|
||||||
"Unarmored",
|
"sSkillUnarmored",
|
||||||
"Security",
|
"sSkillSecurity",
|
||||||
"Sneak",
|
"sSkillSneak",
|
||||||
"Acrobatics",
|
"sSkillAcrobatics",
|
||||||
"Light Armor",
|
"sSkillLightarmor",
|
||||||
"Short Blade",
|
"sSkillShortblade",
|
||||||
"Marksman",
|
"sSkillMarksman",
|
||||||
"Speechcraft",
|
"sSkillMercantile",
|
||||||
"Hand To Hand",
|
"sSkillSpeechcraft",
|
||||||
|
"sSkillHandtohand",
|
||||||
};
|
};
|
||||||
|
const boost::array<Skill::SkillEnum, Skill::Length> Skill::skillIds = {{
|
||||||
|
Block,
|
||||||
|
Armorer,
|
||||||
|
MediumArmor,
|
||||||
|
HeavyArmor,
|
||||||
|
BluntWeapon,
|
||||||
|
LongBlade,
|
||||||
|
Axe,
|
||||||
|
Spear,
|
||||||
|
Athletics,
|
||||||
|
Enchant,
|
||||||
|
Destruction,
|
||||||
|
Alteration,
|
||||||
|
Illusion,
|
||||||
|
Conjuration,
|
||||||
|
Mysticism,
|
||||||
|
Restoration,
|
||||||
|
Alchemy,
|
||||||
|
Unarmored,
|
||||||
|
Security,
|
||||||
|
Sneak,
|
||||||
|
Acrobatics,
|
||||||
|
LightArmor,
|
||||||
|
ShortBlade,
|
||||||
|
Marksman,
|
||||||
|
Mercantile,
|
||||||
|
Speechcraft,
|
||||||
|
HandToHand
|
||||||
|
}};
|
||||||
|
|
||||||
|
void Skill::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(index, "INDX");
|
||||||
|
esm.getHNT(data, "SKDT", 24);
|
||||||
|
description = esm.getHNOString("DESC");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,12 +66,7 @@ struct Skill
|
||||||
static const std::string sSkillNameIds[Length];
|
static const std::string sSkillNameIds[Length];
|
||||||
static const boost::array<SkillEnum, Length> skillIds;
|
static const boost::array<SkillEnum, Length> skillIds;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(index, "INDX");
|
|
||||||
esm.getHNT(data, "SKDT", 24);
|
|
||||||
description = esm.getHNOString("DESC");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
14
components/esm/loadsndg.cpp
Normal file
14
components/esm/loadsndg.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "loadsndg.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void SoundGenerator::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(type, "DATA", 4);
|
||||||
|
|
||||||
|
creature = esm.getHNOString("CNAM");
|
||||||
|
sound = esm.getHNOString("SNAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,13 +28,7 @@ struct SoundGenerator
|
||||||
|
|
||||||
std::string creature, sound;
|
std::string creature, sound;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getHNT(type, "DATA", 4);
|
|
||||||
|
|
||||||
creature = esm.getHNOString("CNAM");
|
|
||||||
sound = esm.getHNOString("SNAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
18
components/esm/loadsoun.cpp
Normal file
18
components/esm/loadsoun.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "loadsoun.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Sound::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
sound = esm.getHNString("FNAM");
|
||||||
|
esm.getHNT(data, "DATA", 3);
|
||||||
|
/*
|
||||||
|
cout << "vol=" << (int)data.volume
|
||||||
|
<< " min=" << (int)data.minRange
|
||||||
|
<< " max=" << (int)data.maxRange
|
||||||
|
<< endl;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,20 +3,20 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct SOUNstruct
|
struct SOUNstruct
|
||||||
{
|
{
|
||||||
unsigned char volume, minRange, maxRange;
|
unsigned char volume, minRange, maxRange;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Sound
|
struct Sound
|
||||||
{
|
{
|
||||||
SOUNstruct data;
|
SOUNstruct data;
|
||||||
std::string sound;
|
std::string sound;
|
||||||
|
|
||||||
// Body moved to load_impl.cpp
|
void load(ESMReader &esm);
|
||||||
void load(ESMReader &esm);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
13
components/esm/loadspel.cpp
Normal file
13
components/esm/loadspel.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "loadspel.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Spell::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(data, "SPDT", 12);
|
||||||
|
effects.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,45 +2,42 @@
|
||||||
#define _ESM_SPEL_H
|
#define _ESM_SPEL_H
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
struct Spell
|
struct Spell
|
||||||
{
|
{
|
||||||
enum SpellType
|
enum SpellType
|
||||||
{
|
{
|
||||||
ST_Spell = 0, // Normal spell, must be cast and costs mana
|
ST_Spell = 0, // Normal spell, must be cast and costs mana
|
||||||
ST_Ability = 1, // Inert ability, always in effect
|
ST_Ability = 1, // Inert ability, always in effect
|
||||||
ST_Blight = 2, // Blight disease
|
ST_Blight = 2, // Blight disease
|
||||||
ST_Disease = 3, // Common disease
|
ST_Disease = 3, // Common disease
|
||||||
ST_Curse = 4, // Curse (?)
|
ST_Curse = 4, // Curse (?)
|
||||||
ST_Power = 5 // Power, can use once a day
|
ST_Power = 5 // Power, can use once a day
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
F_Autocalc = 1,
|
F_Autocalc = 1,
|
||||||
F_PCStart = 2,
|
F_PCStart = 2,
|
||||||
F_Always = 4 // Casting always succeeds
|
F_Always = 4 // Casting always succeeds
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SPDTstruct
|
struct SPDTstruct
|
||||||
{
|
{
|
||||||
int type; // SpellType
|
int type; // SpellType
|
||||||
int cost; // Mana cost
|
int cost; // Mana cost
|
||||||
int flags; // Flags
|
int flags; // Flags
|
||||||
};
|
};
|
||||||
|
|
||||||
SPDTstruct data;
|
SPDTstruct data;
|
||||||
std::string name;
|
std::string name;
|
||||||
EffectList effects;
|
EffectList effects;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(data, "SPDT", 12);
|
|
||||||
effects.load(esm);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
13
components/esm/loadsscr.cpp
Normal file
13
components/esm/loadsscr.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "loadsscr.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void StartScript::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getSubNameIs("DATA");
|
||||||
|
esm.skipHSub();
|
||||||
|
script = esm.getHNString("NAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,27 +3,23 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Startup script. I think this is simply a 'main' script that is run
|
Startup script. I think this is simply a 'main' script that is run
|
||||||
from the begining. The SSCR records contain a DATA identifier which
|
from the begining. The SSCR records contain a DATA identifier which
|
||||||
is totally useless (TODO: don't remember what it contains exactly,
|
is totally useless (TODO: don't remember what it contains exactly,
|
||||||
document it below later.), and a NAME which is simply a script
|
document it below later.), and a NAME which is simply a script
|
||||||
reference.
|
reference.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct StartScript
|
struct StartScript
|
||||||
{
|
{
|
||||||
std::string script;
|
std::string script;
|
||||||
|
|
||||||
// Load a record and add it to the list
|
// Load a record and add it to the list
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
esm.getSubNameIs("DATA");
|
|
||||||
esm.skipHSub();
|
|
||||||
script = esm.getHNString("NAME");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
11
components/esm/loadstat.cpp
Normal file
11
components/esm/loadstat.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "loadstat.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Static::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,10 +21,7 @@ struct Static
|
||||||
{
|
{
|
||||||
std::string model;
|
std::string model;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
16
components/esm/loadweap.cpp
Normal file
16
components/esm/loadweap.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "loadweap.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void Weapon::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
model = esm.getHNString("MODL");
|
||||||
|
name = esm.getHNOString("FNAM");
|
||||||
|
esm.getHNT(data, "WPDT", 32);
|
||||||
|
script = esm.getHNOString("SCRI");
|
||||||
|
icon = esm.getHNOString("ITEX");
|
||||||
|
enchant = esm.getHNOString("ENAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "esm_reader.hpp"
|
#include "esm_reader.hpp"
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Weapon definition
|
* Weapon definition
|
||||||
|
@ -11,58 +12,50 @@ namespace ESM {
|
||||||
|
|
||||||
struct Weapon
|
struct Weapon
|
||||||
{
|
{
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
ShortBladeOneHand = 0,
|
ShortBladeOneHand = 0,
|
||||||
LongBladeOneHand = 1,
|
LongBladeOneHand = 1,
|
||||||
LongBladeTwoHand = 2,
|
LongBladeTwoHand = 2,
|
||||||
BluntOneHand = 3,
|
BluntOneHand = 3,
|
||||||
BluntTwoClose = 4,
|
BluntTwoClose = 4,
|
||||||
BluntTwoWide = 5,
|
BluntTwoWide = 5,
|
||||||
SpearTwoWide = 6,
|
SpearTwoWide = 6,
|
||||||
AxeOneHand = 7,
|
AxeOneHand = 7,
|
||||||
AxeTwoHand = 8,
|
AxeTwoHand = 8,
|
||||||
MarksmanBow = 9,
|
MarksmanBow = 9,
|
||||||
MarksmanCrossbow = 10,
|
MarksmanCrossbow = 10,
|
||||||
MarksmanThrown = 11,
|
MarksmanThrown = 11,
|
||||||
Arrow = 12,
|
Arrow = 12,
|
||||||
Bolt = 13
|
Bolt = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
Magical = 0x01,
|
Magical = 0x01,
|
||||||
Silver = 0x02
|
Silver = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct WPDTstruct
|
struct WPDTstruct
|
||||||
{
|
{
|
||||||
float weight;
|
float weight;
|
||||||
int value;
|
int value;
|
||||||
short type;
|
short type;
|
||||||
short health;
|
short health;
|
||||||
float speed, reach;
|
float speed, reach;
|
||||||
short enchant; // Enchantment points
|
short enchant; // Enchantment points
|
||||||
unsigned char chop[2], slash[2], thrust[2]; // Min and max
|
unsigned char chop[2], slash[2], thrust[2]; // Min and max
|
||||||
int flags;
|
int flags;
|
||||||
}; // 32 bytes
|
}; // 32 bytes
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
WPDTstruct data;
|
WPDTstruct data;
|
||||||
|
|
||||||
std::string name, model, icon, enchant, script;
|
std::string name, model, icon, enchant, script;
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
model = esm.getHNString("MODL");
|
|
||||||
name = esm.getHNOString("FNAM");
|
|
||||||
esm.getHNT(data, "WPDT", 32);
|
|
||||||
script = esm.getHNOString("SCRI");
|
|
||||||
icon = esm.getHNOString("ITEX");
|
|
||||||
enchant = esm.getHNOString("ENAM");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
#include "loadskil.hpp"
|
|
||||||
|
|
||||||
namespace ESM
|
|
||||||
{
|
|
||||||
const std::string Skill::sSkillNameIds[Length] = {
|
|
||||||
"sSkillBlock",
|
|
||||||
"sSkillArmorer",
|
|
||||||
"sSkillMediumarmor",
|
|
||||||
"sSkillHeavyarmor",
|
|
||||||
"sSkillBluntweapon",
|
|
||||||
"sSkillLongblade",
|
|
||||||
"sSkillAxe",
|
|
||||||
"sSkillSpear",
|
|
||||||
"sSkillAthletics",
|
|
||||||
"sSkillEnchant",
|
|
||||||
"sSkillDestruction",
|
|
||||||
"sSkillAlteration",
|
|
||||||
"sSkillIllusion",
|
|
||||||
"sSkillConjuration",
|
|
||||||
"sSkillMysticism",
|
|
||||||
"sSkillRestoration",
|
|
||||||
"sSkillAlchemy",
|
|
||||||
"sSkillUnarmored",
|
|
||||||
"sSkillSecurity",
|
|
||||||
"sSkillSneak",
|
|
||||||
"sSkillAcrobatics",
|
|
||||||
"sSkillLightarmor",
|
|
||||||
"sSkillShortblade",
|
|
||||||
"sSkillMarksman",
|
|
||||||
"sSkillMercantile",
|
|
||||||
"sSkillSpeechcraft",
|
|
||||||
"sSkillHandtohand",
|
|
||||||
};
|
|
||||||
const boost::array<Skill::SkillEnum, Skill::Length> Skill::skillIds = {{
|
|
||||||
Block,
|
|
||||||
Armorer,
|
|
||||||
MediumArmor,
|
|
||||||
HeavyArmor,
|
|
||||||
BluntWeapon,
|
|
||||||
LongBlade,
|
|
||||||
Axe,
|
|
||||||
Spear,
|
|
||||||
Athletics,
|
|
||||||
Enchant,
|
|
||||||
Destruction,
|
|
||||||
Alteration,
|
|
||||||
Illusion,
|
|
||||||
Conjuration,
|
|
||||||
Mysticism,
|
|
||||||
Restoration,
|
|
||||||
Alchemy,
|
|
||||||
Unarmored,
|
|
||||||
Security,
|
|
||||||
Sneak,
|
|
||||||
Acrobatics,
|
|
||||||
LightArmor,
|
|
||||||
ShortBlade,
|
|
||||||
Marksman,
|
|
||||||
Mercantile,
|
|
||||||
Speechcraft,
|
|
||||||
HandToHand
|
|
||||||
}};
|
|
||||||
}
|
|
92
extern/caelum/CMakeLists.txt
vendored
92
extern/caelum/CMakeLists.txt
vendored
|
@ -19,46 +19,52 @@ add_library(caelum STATIC ${SOURCES})
|
||||||
#
|
#
|
||||||
# Resources
|
# Resources
|
||||||
#
|
#
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/AtmosphereDepth.png "${OpenMW_BINARY_DIR}/resources/caelum/AtmosphereDepth.png" COPYONLY)
|
if (APPLE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumGroundFog.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumGroundFog.cg" COPYONLY)
|
SET(CAELUM_RES_DEST "${APP_BUNDLE_DIR}/Contents/Resources")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumLayeredClouds.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumLayeredClouds.cg" COPYONLY)
|
else (APPLE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPhaseMoon.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumPhaseMoon.cg" COPYONLY)
|
SET(CAELUM_RES_DEST "${OpenMW_BINARY_DIR}")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPointStarfield.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumPointStarfield.cg" COPYONLY)
|
endif (APPLE)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumSkyDome.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumSkyDome.cg" COPYONLY)
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CloudCoverLookup.png "${OpenMW_BINARY_DIR}/resources/caelum/CloudCoverLookup.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/AtmosphereDepth.png "${CAELUM_RES_DEST}/resources/caelum/AtmosphereDepth.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.cg "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.cg" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumGroundFog.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumGroundFog.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.compositor "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.compositor" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumLayeredClouds.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumLayeredClouds.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.material "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPhaseMoon.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumPhaseMoon.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthRender.program "${OpenMW_BINARY_DIR}/resources/caelum/DepthRender.program" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPointStarfield.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumPointStarfield.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/EarthClearSky2.png "${OpenMW_BINARY_DIR}/resources/caelum/EarthClearSky2.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumSkyDome.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumSkyDome.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.material "${OpenMW_BINARY_DIR}/resources/caelum/GroundFog.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CloudCoverLookup.png "${CAELUM_RES_DEST}/resources/caelum/CloudCoverLookup.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.program "${OpenMW_BINARY_DIR}/resources/caelum/GroundFog.program" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.cg "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Haze.program "${OpenMW_BINARY_DIR}/resources/caelum/Haze.program" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.compositor "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.compositor" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/LayeredClouds.material "${OpenMW_BINARY_DIR}/resources/caelum/LayeredClouds.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.material "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.material" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.cg "${OpenMW_BINARY_DIR}/resources/caelum/MinimalCompositorVP.cg" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthRender.program "${CAELUM_RES_DEST}/resources/caelum/DepthRender.program" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.program "${OpenMW_BINARY_DIR}/resources/caelum/MinimalCompositorVP.program" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/EarthClearSky2.png "${CAELUM_RES_DEST}/resources/caelum/EarthClearSky2.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon.material "${OpenMW_BINARY_DIR}/resources/caelum/moon.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.material "${CAELUM_RES_DEST}/resources/caelum/GroundFog.material" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon_disc.dds "${OpenMW_BINARY_DIR}/resources/caelum/moon_disc.dds" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.program "${CAELUM_RES_DEST}/resources/caelum/GroundFog.program" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise1.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise1.dds" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Haze.program "${CAELUM_RES_DEST}/resources/caelum/Haze.program" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise2.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise2.dds" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/LayeredClouds.material "${CAELUM_RES_DEST}/resources/caelum/LayeredClouds.material" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise3.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise3.dds" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.cg "${CAELUM_RES_DEST}/resources/caelum/MinimalCompositorVP.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise4.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise4.dds" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.program "${CAELUM_RES_DEST}/resources/caelum/MinimalCompositorVP.program" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/PointStarfield.material "${OpenMW_BINARY_DIR}/resources/caelum/PointStarfield.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon.material "${CAELUM_RES_DEST}/resources/caelum/moon.material" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.cg "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.cg" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon_disc.dds "${CAELUM_RES_DEST}/resources/caelum/moon_disc.dds" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.compositor "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.compositor" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise1.dds "${CAELUM_RES_DEST}/resources/caelum/noise1.dds" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.material "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise2.dds "${CAELUM_RES_DEST}/resources/caelum/noise2.dds" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_drizzle.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_drizzle.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise3.dds "${CAELUM_RES_DEST}/resources/caelum/noise3.dds" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_hail.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_hail.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise4.dds "${CAELUM_RES_DEST}/resources/caelum/noise4.dds" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icecrystals.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_icecrystals.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/PointStarfield.material "${CAELUM_RES_DEST}/resources/caelum/PointStarfield.material" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icepellets.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_icepellets.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.cg "${CAELUM_RES_DEST}/resources/caelum/Precipitation.cg" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_rain.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_rain.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.compositor "${CAELUM_RES_DEST}/resources/caelum/Precipitation.compositor" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_smallhail.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_smallhail.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.material "${CAELUM_RES_DEST}/resources/caelum/Precipitation.material" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snow.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_snow.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_drizzle.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_drizzle.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snowgrains.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_snowgrains.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_hail.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_hail.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SkyDome.material "${OpenMW_BINARY_DIR}/resources/caelum/SkyDome.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icecrystals.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_icecrystals.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sphere.mesh "${OpenMW_BINARY_DIR}/resources/caelum/sphere.mesh" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icepellets.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_icepellets.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.jpg "${OpenMW_BINARY_DIR}/resources/caelum/Starfield.jpg" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_rain.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_rain.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.material "${OpenMW_BINARY_DIR}/resources/caelum/Starfield.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_smallhail.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_smallhail.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Sun.material "${OpenMW_BINARY_DIR}/resources/caelum/Sun.material" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snow.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_snow.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SunGradient.png "${OpenMW_BINARY_DIR}/resources/caelum/SunGradient.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snowgrains.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_snowgrains.png" COPYONLY)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sun_disc.png "${OpenMW_BINARY_DIR}/resources/caelum/sun_disc.png" COPYONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SkyDome.material "${CAELUM_RES_DEST}/resources/caelum/SkyDome.material" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sphere.mesh "${CAELUM_RES_DEST}/resources/caelum/sphere.mesh" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.jpg "${CAELUM_RES_DEST}/resources/caelum/Starfield.jpg" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.material "${CAELUM_RES_DEST}/resources/caelum/Starfield.material" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Sun.material "${CAELUM_RES_DEST}/resources/caelum/Sun.material" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SunGradient.png "${CAELUM_RES_DEST}/resources/caelum/SunGradient.png" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sun_disc.png "${CAELUM_RES_DEST}/resources/caelum/sun_disc.png" COPYONLY)
|
||||||
|
|
6
extern/mygui_3.0.1/CMakeLists.txt
vendored
6
extern/mygui_3.0.1/CMakeLists.txt
vendored
|
@ -22,7 +22,11 @@ add_subdirectory(OgrePlatform)
|
||||||
|
|
||||||
# Copy resource files into the build directory
|
# Copy resource files into the build directory
|
||||||
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}/openmw_resources)
|
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}/openmw_resources)
|
||||||
set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui)
|
if (APPLE)
|
||||||
|
set(DDIR ${APP_BUNDLE_DIR}/Contents/Resources/resources/mygui)
|
||||||
|
else (APPLE)
|
||||||
|
set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui)
|
||||||
|
endif (APPLE)
|
||||||
|
|
||||||
configure_file("${SDIR}/bigbars.png" "${DDIR}/bigbars.png" COPYONLY)
|
configure_file("${SDIR}/bigbars.png" "${DDIR}/bigbars.png" COPYONLY)
|
||||||
configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY)
|
configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Defines plugins to load
|
# Defines plugins to load
|
||||||
|
|
||||||
# Define plugin folder
|
# Define plugin folder
|
||||||
PluginFolder=${OGRE_PLUGIN_DIR}
|
PluginFolder=
|
||||||
|
|
||||||
# Define plugins
|
# Define plugins
|
||||||
Plugin=RenderSystem_GL.dylib
|
Plugin=RenderSystem_GL.dylib
|
||||||
|
|
Loading…
Reference in a new issue