Merge remote branch 'corristo/header-refactoring' into header-refactoring

Conflicts:
	CMakeLists.txt
This commit is contained in:
Marc Zinnschlag 2011-04-08 19:24:21 +02:00
commit 7c506301b7
88 changed files with 2628 additions and 2157 deletions

View file

@ -1,5 +1,9 @@
project(OpenMW)
IF (APPLE)
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/OpenMW.app")
ENDIF (APPLE)
# Sound source selection
option(USE_AUDIERE "use Audiere for sound" OFF)
option(USE_FFMPEG "use ffmpeg for sound" OFF)
@ -14,7 +18,7 @@ if(DPKG_PROGRAM)
else()
if (APPLE)
# 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")
else()
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)
set(ESM
${COMP_DIR}/esm/load_impl.cpp
${COMP_DIR}/esm/skill.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})
@ -286,25 +328,50 @@ add_definitions(-DCAELUM_STATIC)
# 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
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)
endif (WIN32)
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")
endif()
if (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac
"${OpenMW_BINARY_DIR}/plugins.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac
"${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)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg")
# Compiler settings
if (CMAKE_COMPILER_IS_GNUCC)
@ -315,10 +382,15 @@ endif (CMAKE_COMPILER_IS_GNUCC)
# Apple bundling
if (APPLE)
set(MISC_FILES
${OpenMW_BINARY_DIR}/openmw.cfg
${OpenMW_BINARY_DIR}/plugins.cfg)
${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg
${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg)
set(OGRE_PLUGINS
${APP_BUNDLE_DIR}/Contents/Plugins/*)
install(FILES ${MISC_FILES} DESTINATION ../MacOS)
install(DIRECTORY "${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_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist")
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns")

View file

@ -49,8 +49,8 @@ Getting OpenMW Working
--link-shared,static --prefix=$OMW_LIB_PREFIX install
5. Download [Ogre][] SDK (tested with 1.7.2) and move `lib/Release/Ogre.framework` into
`Library/Frameworks`.
5. Download [Ogre][] SDK (tested with 1.7.2), unpack it and move
`lib/Release/Ogre.framework` into `Library/Frameworks`.
6. Download [OIS][] and use the XCode project provided in
`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
$ cmake \
-D CMAKE_OSX_ARCHITECTURES=i386 \
-D OGRESDK=/path/to/ogre/sdk \
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
@ -109,31 +110,16 @@ Getting OpenMW Working
if you prefer Eclipse. You also can specify -D CMAKE_BUILD_TYPE=Debug for debug
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:
$ 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:
$ ./openmw
12. From your build directory run:
$ OpenMW.app/Contents/MacOS/openmw
or:
$ open OpenMW.app
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

View file

@ -12,9 +12,9 @@
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
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
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
MESSAGE(STATUS "Looking for OGRE")
@ -47,7 +47,16 @@ IF (UNIX AND NOT APPLE)
PKG_CHECK_MODULES(OGRE OGRE)
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 (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
PATHS
/Library/Frameworks
@ -71,7 +80,12 @@ SET(OGRE_LIB_DIR ${OGRE_LIB_DIR} CACHE PATH "")
if(OGRE_LIB_DIR)
CMAKE_POLICY(SET CMP0009 NEW)
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})
STRING(REGEX REPLACE "/[^/]*$" "" OGRE_PLUGIN_DIR ${OGRE_PLUGINS_FILE})
ENDFOREACH(OGRE_PLUGINS_FILE)
@ -85,6 +99,7 @@ IF (OGRE_FOUND)
IF (NOT OGRE_FIND_QUIETLY)
MESSAGE(STATUS " libraries : ${OGRE_LIBRARIES} from ${OGRE_LIB_DIR}")
MESSAGE(STATUS " includes : ${OGRE_INCLUDE_DIR}")
MESSAGE(STATUS " plugins : ${OGRE_PLUGIN_DIR}")
ENDIF (NOT OGRE_FIND_QUIETLY)
ELSE (OGRE_FOUND)
IF (OGRE_FIND_REQUIRED)

View file

@ -3,13 +3,14 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
typedef int32_t Color;
enum VarType
{
{
VT_Unknown,
VT_None,
VT_Short,
@ -18,39 +19,35 @@ enum VarType
VT_Float,
VT_String,
VT_Ignored
};
};
enum Specialization
{
SPC_Combat = 0,
SPC_Magic = 1,
SPC_Stealth = 2
};
{
SPC_Combat = 0, SPC_Magic = 1, SPC_Stealth = 2
};
enum RangeType
{
RT_Self = 0,
RT_Touch = 1,
RT_Target = 2
};
{
RT_Self = 0, RT_Touch = 1, RT_Target = 2
};
/** A list of references to spells and spell effects. This is shared
between the records BSGN, NPC and RACE.
*/
*/
struct SpellList
{
std::vector<std::string> list;
void load(ESMReader &esm)
{
while(esm.isNextSub("NPCS"))
while (esm.isNextSub("NPCS"))
list.push_back(esm.getHString());
}
};
/** Defines a spell effect. Shared between SPEL (Spells), ALCH
(Potions) and ENCH (Item enchantments) records
*/
*/
#pragma pack(push)
#pragma pack(1)
@ -85,7 +82,7 @@ struct EffectList
void load(ESMReader &esm)
{
ENAMstruct s;
while(esm.isNextSub("ENAM"))
while (esm.isNextSub("ENAM"))
{
esm.getHT(s, 24);
list.push_back(s);

View 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());
}
}

View file

@ -171,122 +171,27 @@ public:
/** Save the current file position and information in a ESM_Context
struct
*/
ESM_Context getContext()
{
// Update the file position before returning
mCtx.filePos = mEsm->tell();
return mCtx;
}
ESM_Context getContext();
/** Restore a previously saved context */
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);
}
void restoreContext(const ESM_Context &rc);
/** Close the file, resets all information. After calling close()
the structure may be reused to load a new file.
*/
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;
}
void close();
/// Raw opening. Opens the file and sets everything up but doesn't
/// parse the header.
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;
}
void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name);
/// Load ES file from a new stream, parses the header. Closes the
/// currently open file first, if any.
void open(Mangle::Stream::StreamPtr _esm, const std::string &name)
{
openRaw(_esm, name);
void open(Mangle::Stream::StreamPtr _esm, const std::string &name);
if(getRecName() != "TES3")
fail("Not a valid Morrowind file");
void open(const std::string &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 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);
}
void openRaw(const std::string &file);
/*************************************************************************
*
@ -320,19 +225,14 @@ public:
getHT(x);
}
int64_t getHNLong(const char *name)
{
int64_t val;
getHNT(val, name);
return val;
}
int64_t getHNLong(const char *name);
// Get data of a given type/size, including subrecord header
template <typename X>
void getHT(X &x)
{
getSubHeader();
if(mCtx.leftSub != sizeof(X))
if (mCtx.leftSub != sizeof(X))
fail("getHT(): subrecord size mismatch");
getT(x);
}
@ -347,57 +247,19 @@ public:
}
// Read a string by the given name if it is the next record.
std::string getHNOString(const char* name)
{
if(isNextSub(name))
return getHString();
return "";
}
std::string getHNOString(const char* name);
// Read a string with the given sub-record name
std::string getHNString(const char* name)
{
getSubNameIs(name);
return getHString();
}
std::string getHNString(const char* name);
// Read a string, including the sub-record header (but not the name)
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);
}
std::string getHString();
// Read the given number of bytes from a subrecord
void getHExact(void*p, int size)
{
getSubHeader();
if(size !=static_cast<int> (mCtx.leftSub))
fail("getHExact() size mismatch");
getExact(p,size);
}
void getHExact(void*p, int size);
// Read the given number of bytes from a named subrecord
void getHNExact(void*p, int size, const char* name)
{
getSubNameIs(name);
getHExact(p,size);
}
void getHNExact(void*p, int size, const char* name);
/*************************************************************************
*
@ -406,100 +268,37 @@ public:
*************************************************************************/
// Get the next subrecord name and check if it matches the parameter
void getSubNameIs(const char* name)
{
getSubName();
if(mCtx.subName != name)
fail("Expected subrecord " + std::string(name) + " but got " + mCtx.subName.toString());
}
void getSubNameIs(const char* name);
/** Checks if the next sub record name matches the parameter. If it
does, it is read into 'subName' just as if getSubName() was
called. If not, the read name will still be available for future
calls to getSubName(), isNextSub() and getSubNameIs().
*/
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;
}
bool isNextSub(const char* name);
// Read subrecord name. This gets called a LOT, so I've optimized it
// slightly.
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;
}
void getSubName();
// This is specially optimized for LoadINFO.
bool isEmptyOrGetName()
{
if(mCtx.leftRec)
{
mEsm->read(mCtx.subName.name, 4);
mCtx.leftRec -= 4;
return false;
}
return true;
}
bool isEmptyOrGetName();
// Skip current sub record, including header (but not including
// name.)
void skipHSub()
{
getSubHeader();
skip(mCtx.leftSub);
}
void skipHSub();
// Skip sub record and check its size
void skipHSubSize(int size)
{
skipHSub();
if(static_cast<int> (mCtx.leftSub) != size)
fail("skipHSubSize() mismatch");
}
void skipHSubSize(int size);
/* Sub-record header. This updates leftRec beyond the current
sub-record as well. leftSub contains size of current sub-record.
*/
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;
}
void getSubHeader();
/** Get sub header and check the size
*/
void getSubHeaderIs(int size)
{
getSubHeader();
if(size != static_cast<int> (mCtx.leftSub))
fail("getSubHeaderIs(): Sub header mismatch");
}
void getSubHeaderIs(int size);
/*************************************************************************
*
@ -508,62 +307,21 @@ public:
*************************************************************************/
// Get the next record name
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;
}
NAME getRecName();
// Skip the rest of this record. Assumes the name and header have
// already been read
void skipRecord()
{
skip(mCtx.leftRec);
mCtx.leftRec = 0;
}
void skipRecord();
// Skip an entire record, including the header (but not the name)
void skipHRecord()
{
if(!mCtx.leftFile) return;
getRecHeader();
skipRecord();
}
void skipHRecord();
/* Read record header. This updatesleftFile BEYOND the data that
follows the header, ie beyond the entire record. You should use
leftRec to orient yourself inside the record itself.
*/
void getRecHeader() { uint32_t u; getRecHeader(u); }
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;
}
void getRecHeader(uint32_t &flags);
bool hasMoreRecs() { return mCtx.leftFile > 0; }
bool hasMoreSubs() { return mCtx.leftRec > 0; }
@ -578,44 +336,19 @@ public:
template <typename X>
void getT(X &x) { getExact(&x, sizeof(X)); }
void getExact(void*x, int size)
{
int t = mEsm->read(x, size);
if(t != size)
fail("Read error");
}
void getExact(void*x, int size);
void getName(NAME &name) { getT(name); }
void getUint(uint32_t &u) { getT(u); }
// Read the next 'size' bytes and return them as a string. Converts
// them from native encoding to UTF8 in the process.
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);
}
std::string getString(int size);
void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
uint64_t getOffset() { return mEsm->tell(); }
/// Used for error handling
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());
}
void fail(const std::string &msg);
private:
Mangle::Stream::StreamPtr mEsm;

View file

@ -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;
*/
}
}

View 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");
}
}

View file

@ -3,18 +3,14 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct Activator
{
std::string name, script, model;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
script = esm.getHNOString("SCRI");
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Alchemy item (potions)
@ -23,15 +24,7 @@ struct Potion
std::string name, model, icon, script;
EffectList effects;
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);
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Alchemist apparatus
@ -13,10 +14,7 @@ struct Apparatus
{
enum AppaType
{
MortarPestle = 0,
Albemic = 1,
Calcinator = 2,
Retort = 3
MortarPestle = 0, Albemic = 1, Calcinator = 2, Retort = 3
};
struct AADTstruct
@ -30,14 +28,7 @@ struct Apparatus
AADTstruct data;
std::string model, icon, script, name;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,10 +3,11 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
enum PartReferenceType
{
{
PRT_Head = 0,
PRT_Hair = 1,
PRT_Neck = 2,
@ -34,7 +35,7 @@ enum PartReferenceType
PRT_LPauldron = 24,
PRT_Weapon = 25,
PRT_Tail = 26
};
};
// Reference to body parts
struct PartReference
@ -48,16 +49,7 @@ struct PartReferenceList
{
std::vector<PartReference> parts;
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");
}
}
void load(ESMReader &esm);
};
struct Armor
@ -89,16 +81,7 @@ struct Armor
std::string name, model, icon, script, enchant;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct BodyPart
{
@ -28,15 +29,12 @@ struct BodyPart
enum Flags
{
BPF_Female = 1,
BPF_Playable = 2
BPF_Female = 1, BPF_Playable = 2
};
enum MeshType
{
MT_Skin = 0,
MT_Clothing = 1,
MT_Armor = 2
MT_Skin = 0, MT_Clothing = 1, MT_Armor = 2
};
struct BYDTstruct
@ -50,12 +48,7 @@ struct BodyPart
BYDTstruct data;
std::string model, name;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
esm.getHNT(data, "BYDT", 4);
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Books, magic scrolls, notes and so on
@ -20,16 +21,7 @@ struct Book
BKDTstruct data;
std::string name, model, icon, script, enchant, text;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}

View file

@ -4,7 +4,8 @@
#include "defs.hpp"
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct BirthSign
{
@ -13,14 +14,7 @@ struct BirthSign
// List of powers and abilities that come with this birth sign.
SpellList powers;
void load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
texture = esm.getHNOString("TNAM");
description = esm.getHNOString("DESC");
powers.load(esm);
};
void load(ESMReader &esm);
};
}
#endif

113
components/esm/loadcell.cpp Normal file
View 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;
}
}

View file

@ -117,51 +117,14 @@ struct Cell
int water; // Water level
int mapColor;
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();
}
void load(ESMReader &esm);
// 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
// somewhere other than the file system, you need to pre-open the
// ESMReader, and the filename must match the stored filename
// exactly.
void restore(ESMReader &esm) const
{ esm.restoreContext(context); }
void restore(ESMReader &esm) const;
/* Get the next reference in this cell, if any. Returns false when
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
reuse one memory location without blanking it between calls.
*/
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;
}
static bool getNextRef(ESMReader &esm, CellRef &ref);
};
}
#endif

View file

@ -1,6 +1,7 @@
#include "loadclas.hpp"
using namespace ESM;
namespace ESM
{
const Class::Specialization Class::specializationIds[3] = {
Class::Combat,
@ -13,3 +14,16 @@ const char *Class::gmstSpecializationIds[3] = {
"sSpecializationMagic",
"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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Character class definitions
@ -37,9 +38,7 @@ struct Class
enum Specialization
{
Combat = 0,
Magic = 1,
Stealth = 2
Combat = 0, Magic = 1, Stealth = 2
};
static const Specialization specializationIds[3];
@ -59,16 +58,7 @@ struct Class
std::string name, description;
CLDTstruct data;
void 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");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "loadarmo.hpp"
namespace ESM {
namespace ESM
{
/*
* Clothing
@ -39,19 +40,7 @@ struct Clothing
std::string name, model, icon, enchant, script;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Container definition
@ -19,15 +20,7 @@ struct InventoryList
{
std::vector<ContItem> list;
void load(ESMReader &esm)
{
ContItem ci;
while(esm.isNextSub("NPCO"))
{
esm.getHT(ci, 36);
list.push_back(ci);
}
}
void load(ESMReader &esm);
};
struct Container
@ -45,20 +38,7 @@ struct Container
int flags;
InventoryList inventory;
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);
}
void load(ESMReader &esm);
};
}
#endif

View 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();
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "loadcont.hpp"
namespace ESM {
namespace ESM
{
/*
* Creature definition
@ -16,24 +17,20 @@ struct Creature
// Default is 0x48?
enum Flags
{
Biped = 0x001,
Respawn = 0x002,
Weapon = 0x004, // Has weapon and shield
Biped = 0x001, Respawn = 0x002, Weapon = 0x004, // Has weapon and shield
None = 0x008, // ??
Swims = 0x010,
Flies = 0x020, // Don't know what happens if several
Walks = 0x040, // of these are set
Essential = 0x080,
Skeleton = 0x400, // Does not have normal blood
Metal = 0x800 // Has 'golden' blood
Metal = 0x800
// Has 'golden' blood
};
enum Type
{
Creatures = 0,
Deadra = 1,
Undead = 2,
Humanoid = 3
Creatures = 0, Deadra = 1, Undead = 2, Humanoid = 3
};
struct NPDTstruct
@ -56,48 +53,14 @@ struct Creature
int flags;
float scale;
std::string model, name, script,
original; // Base creature that this is a modification of
std::string model, name, script, original; // Base creature that this is a modification of
// Defined in loadcont.hpp
InventoryList inventory;
std::string mId;
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();
}
void load(ESMReader &esm, const std::string& id);
};
}
#endif

View 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");
}
}

View file

@ -6,7 +6,8 @@
#include "esm_reader.hpp"
#include "loadinfo.hpp"
namespace ESM {
namespace ESM
{
/*
* Dialogue topic and journal entries. The actual data is contained in
@ -28,23 +29,7 @@ struct Dialogue
char type;
std::vector<DialInfo> mInfo;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,20 +3,14 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct Door
{
std::string name, model, script, openSound, closeSound;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
script = esm.getHNOString("SCRI");
openSound = esm.getHNOString("SNAM");
closeSound = esm.getHNOString("ANAM");
}
void load(ESMReader &esm);
};
}
#endif

View file

@ -0,0 +1,12 @@
#include "loadench.hpp"
namespace ESM
{
void Enchantment::load(ESMReader &esm)
{
esm.getHNT(data, "ENDT", 16);
effects.load(esm);
}
}

View file

@ -2,8 +2,10 @@
#define _ESM_ENCH_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Enchantments
@ -31,11 +33,7 @@ struct Enchantment
ENDTstruct data;
EffectList effects;
void load(ESMReader &esm)
{
esm.getHNT(data, "ENDT", 16);
effects.load(esm);
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Faction definitions
@ -51,28 +52,7 @@ struct Faction
// Name of faction ranks (may be empty for NPC factions)
std::string ranks[10];
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);
}
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -2,8 +2,10 @@
#define _ESM_GLOB_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Global script variables
@ -14,19 +16,7 @@ struct Global
unsigned value;
VarType type;
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");
}
void load(ESMReader &esm);
};
}
#endif

172
components/esm/loadgmst.cpp Normal file
View 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;
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Game setting, with automatic cleaning of "dirty" entries.
@ -72,179 +73,16 @@ struct GameSetting
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
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;
}
bool isDirtyTribunal();
// Bloodmoon variant
bool 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.'
bool isDirtyBloodmoon();
// 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;
}
#undef cI
#undef cF
#undef cS
void 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;
}
void load(ESMReader &esm);
};
}
#endif

133
components/esm/loadinfo.cpp Normal file
View 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();
}
}

View file

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
// NOT DONE

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Alchemy ingredient
@ -23,14 +24,7 @@ struct Ingredient
IRDTstruct data;
std::string name, model, icon, script;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}

View file

@ -3,8 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Landscape data.
*/
@ -21,33 +21,7 @@ struct Land
bool hasData;
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);
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Leveled lists. Since these have identical layout, I only bothered
@ -41,39 +42,24 @@ struct LeveledListBase
std::vector<LevelItem> list;
void load(ESMReader &esm)
{
esm.getHNT(flags, "DATA");
esm.getHNT(chanceNone, "NNAM");
void load(ESMReader &esm);
};
if(esm.isNextSub("INDX"))
struct CreatureLevList: LeveledListBase
{
CreatureLevList()
{
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");
}
recName = "CNAM";
}
};
struct CreatureLevList : LeveledListBase
{ CreatureLevList() { recName = "CNAM"; } };
struct ItemLevList : LeveledListBase
{ ItemLevList() { recName = "INAM"; } };
struct ItemLevList: LeveledListBase
{
ItemLevList()
{
recName = "INAM";
}
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Lights. Includes static light sources and also carryable candles
@ -39,16 +40,7 @@ struct Light
std::string sound, script, model, icon, name;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* This file covers lockpicks (LOCK), probes (PROB) and armor repair
@ -26,37 +27,15 @@ struct Tool
Data data;
std::string name, model, icon, script;
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");
}
void load(ESMReader &esm);
};
struct Probe : Tool
struct Probe: Tool
{
};
struct Repair : Tool
struct Repair: Tool
{
};

View file

@ -0,0 +1,12 @@
#include "loadltex.hpp"
namespace ESM
{
void LandTexture::load(ESMReader &esm)
{
esm.getHNT(index, "INTV");
texture = esm.getHNString("DATA");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Texture used for texturing landscape.
@ -26,11 +27,7 @@ struct LandTexture
std::string id, texture;
int index;
void load(ESMReader &esm)
{
esm.getHNT(index, "INTV");
texture = esm.getHNString("DATA");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct MagicEffect
{
@ -30,8 +31,7 @@ struct MagicEffect
std::string icon, particle, // Textures
casting, hit, area, // Statics
bolt, // Weapon
castSound, boltSound,
hitSound, areaSound, // Sounds
castSound, boltSound, hitSound, areaSound, // Sounds
description;
// Index of this magical effect. Corresponds to one of the
@ -45,26 +45,7 @@ struct MagicEffect
// sMagicCreature04ID/05ID.
int index;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Misc inventory items, basically things that have no use but can be
@ -24,14 +25,7 @@ struct Misc
std::string name, model, icon, script;
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");
}
void load(ESMReader &esm);
};
}
#endif

View 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();
}
}

View 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");
}
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Path grid.
@ -23,34 +24,7 @@ struct PathGrid
ESM_Context context; // Context so we can return here later and
// finish the job
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");
}
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -2,8 +2,10 @@
#define _ESM_RACE_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Race definition
@ -39,8 +41,8 @@ struct Race
SkillBonus bonus[7];
// Attribute values for male/female
MaleFemale strength, intelligence, willpower, agility,
speed, endurance, personality, luck;
MaleFemale strength, intelligence, willpower, agility, speed,
endurance, personality, luck;
// The actual eye level height (in game units) is (probably) given
// as 'height' times 128. This has not been tested yet.
@ -48,21 +50,14 @@ struct Race
int flags; // 0x1 - playable, 0x2 - beast race
// Size = 140 bytes
};
}; // Size = 140 bytes
RADTstruct data;
std::string name, description;
SpellList powers;
void load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
esm.getHNT(data, "RADT", 140);
powers.load(esm);
description = esm.getHNOString("DESC");
}
void load(ESMReader &esm);
};
}
#endif

View 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);
}
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Region data
@ -16,11 +17,10 @@ struct Region
struct WEATstruct
{
// I guess these are probabilities
char clear, cloudy, foggy, overcast, rain, thunder, ash,
blight,
char clear, cloudy, foggy, overcast, rain, thunder, ash, blight,
// Unknown weather, probably snow and something. Only
// present in file version 1.3.
a,b;
a, b;
}; // 10 bytes
// Reference to a sound that is played randomly in this region
@ -40,27 +40,7 @@ struct Region
std::vector<SoundRef> soundList;
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);
}
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Script definitions
@ -39,8 +40,7 @@ public:
// These describe the sizes we need to allocate for the script
// data.
int numShorts, numLongs, numFloats,
scriptDataSize, stringTableSize;
int numShorts, numLongs, numFloats, scriptDataSize, stringTableSize;
}; // 52 bytes
SCHDstruct data;
@ -49,43 +49,7 @@ public:
std::vector<char> scriptData; // Compiled bytecode
std::string scriptText; // Uncompiled script
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");
}
void load(ESMReader &esm);
};
}
#endif

View file

@ -1,33 +1,70 @@
#include "loadskil.hpp"
namespace ESMS
namespace ESM
{
const std::string Skill::sSkillNames[Length] = {
"Block",
"Armorer",
"Medium Armor",
"Heavy Armor",
"Blunt Weapon",
"Long Blade",
"Axe",
"Spear",
"Athletics",
"Enchant",
"Destruction",
"Alteration",
"Illusion",
"Conjuration",
"Mysticism",
"Restoration",
"Alchemy",
"Unarmored",
"Security",
"Sneak",
"Acrobatics",
"Light Armor",
"Short Blade",
"Marksman",
"Speechcraft",
"Hand To Hand",
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
}};
void Skill::load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "SKDT", 24);
description = esm.getHNOString("DESC");
}
}

View file

@ -66,12 +66,7 @@ struct Skill
static const std::string sSkillNameIds[Length];
static const boost::array<SkillEnum, Length> skillIds;
void load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "SKDT", 24);
description = esm.getHNOString("DESC");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -28,13 +28,7 @@ struct SoundGenerator
std::string creature, sound;
void load(ESMReader &esm)
{
esm.getHNT(type, "DATA", 4);
creature = esm.getHNOString("CNAM");
sound = esm.getHNOString("SNAM");
}
void load(ESMReader &esm);
};
}
#endif

View 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;
*/
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct SOUNstruct
{
@ -15,7 +16,6 @@ struct Sound
SOUNstruct data;
std::string sound;
// Body moved to load_impl.cpp
void load(ESMReader &esm);
};
}

View 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);
}
}

View file

@ -2,8 +2,10 @@
#define _ESM_SPEL_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
struct Spell
{
@ -35,12 +37,7 @@ struct Spell
std::string name;
EffectList effects;
void load(ESMReader &esm)
{
name = esm.getHNOString("FNAM");
esm.getHNT(data, "SPDT", 12);
effects.load(esm);
}
void load(ESMReader &esm);
};
}
#endif

View file

@ -0,0 +1,13 @@
#include "loadsscr.hpp"
namespace ESM
{
void StartScript::load(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.skipHSub();
script = esm.getHNString("NAME");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
Startup script. I think this is simply a 'main' script that is run
@ -18,12 +19,7 @@ struct StartScript
std::string script;
// Load a record and add it to the list
void load(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.skipHSub();
script = esm.getHNString("NAME");
}
void load(ESMReader &esm);
};
}

View file

@ -0,0 +1,11 @@
#include "loadstat.hpp"
namespace ESM
{
void Static::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
}
}

View file

@ -21,10 +21,7 @@ struct Static
{
std::string model;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
}
void load(ESMReader &esm);
};
}
#endif

View 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");
}
}

View file

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Weapon definition
@ -54,15 +55,7 @@ struct Weapon
std::string name, model, icon, enchant, script;
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");
}
void load(ESMReader &esm);
};
}
#endif

View file

@ -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
}};
}

View file

@ -19,46 +19,52 @@ add_library(caelum STATIC ${SOURCES})
#
# Resources
#
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/AtmosphereDepth.png "${OpenMW_BINARY_DIR}/resources/caelum/AtmosphereDepth.png" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumGroundFog.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumGroundFog.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumLayeredClouds.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumLayeredClouds.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPhaseMoon.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumPhaseMoon.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPointStarfield.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumPointStarfield.cg" COPYONLY)
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/DepthComposer.cg "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.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/DepthComposer.material "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.material" 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/EarthClearSky2.png "${OpenMW_BINARY_DIR}/resources/caelum/EarthClearSky2.png" 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/GroundFog.program "${OpenMW_BINARY_DIR}/resources/caelum/GroundFog.program" 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/LayeredClouds.material "${OpenMW_BINARY_DIR}/resources/caelum/LayeredClouds.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/MinimalCompositorVP.program "${OpenMW_BINARY_DIR}/resources/caelum/MinimalCompositorVP.program" 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/moon_disc.dds "${OpenMW_BINARY_DIR}/resources/caelum/moon_disc.dds" 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/noise2.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise2.dds" 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/noise4.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise4.dds" 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/Precipitation.cg "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.cg" 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/Precipitation.material "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.material" 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/precipitation_hail.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_hail.png" 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/precipitation_icepellets.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_icepellets.png" 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_smallhail.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_smallhail.png" 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_snowgrains.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_snowgrains.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/sphere.mesh "${OpenMW_BINARY_DIR}/resources/caelum/sphere.mesh" 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/Starfield.material "${OpenMW_BINARY_DIR}/resources/caelum/Starfield.material" 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/SunGradient.png "${OpenMW_BINARY_DIR}/resources/caelum/SunGradient.png" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sun_disc.png "${OpenMW_BINARY_DIR}/resources/caelum/sun_disc.png" COPYONLY)
if (APPLE)
SET(CAELUM_RES_DEST "${APP_BUNDLE_DIR}/Contents/Resources")
else (APPLE)
SET(CAELUM_RES_DEST "${OpenMW_BINARY_DIR}")
endif (APPLE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/AtmosphereDepth.png "${CAELUM_RES_DEST}/resources/caelum/AtmosphereDepth.png" 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/CaelumLayeredClouds.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumLayeredClouds.cg" 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/CaelumPointStarfield.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumPointStarfield.cg" 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/CloudCoverLookup.png "${CAELUM_RES_DEST}/resources/caelum/CloudCoverLookup.png" 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/DepthComposer.compositor "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.compositor" 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/DepthRender.program "${CAELUM_RES_DEST}/resources/caelum/DepthRender.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/GroundFog.material "${CAELUM_RES_DEST}/resources/caelum/GroundFog.material" 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/Haze.program "${CAELUM_RES_DEST}/resources/caelum/Haze.program" 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/MinimalCompositorVP.cg "${CAELUM_RES_DEST}/resources/caelum/MinimalCompositorVP.cg" 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/moon.material "${CAELUM_RES_DEST}/resources/caelum/moon.material" 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/noise1.dds "${CAELUM_RES_DEST}/resources/caelum/noise1.dds" 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/noise3.dds "${CAELUM_RES_DEST}/resources/caelum/noise3.dds" 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/PointStarfield.material "${CAELUM_RES_DEST}/resources/caelum/PointStarfield.material" 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.compositor "${CAELUM_RES_DEST}/resources/caelum/Precipitation.compositor" 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_drizzle.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_drizzle.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/precipitation_icecrystals.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_icecrystals.png" 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/precipitation_rain.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_rain.png" 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/precipitation_snow.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_snow.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/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)

View file

@ -22,7 +22,11 @@ add_subdirectory(OgrePlatform)
# Copy resource files into the build directory
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}/black.png" "${DDIR}/black.png" COPYONLY)

View file

@ -1,7 +1,7 @@
# Defines plugins to load
# Define plugin folder
PluginFolder=${OGRE_PLUGIN_DIR}
PluginFolder=
# Define plugins
Plugin=RenderSystem_GL.dylib