mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-01 01:45:36 +00:00
Merge branch 'master' of https://github.com/zinnschlag/openmw into DragDrop
This commit is contained in:
commit
569533eeae
109 changed files with 2786 additions and 1017 deletions
18
.travis.yml
18
.travis.yml
|
@ -4,17 +4,17 @@ compiler:
|
|||
branches:
|
||||
only:
|
||||
- master
|
||||
- next
|
||||
- /openmw-.*$/
|
||||
before_install:
|
||||
- pwd
|
||||
- git submodule update --init --recursive
|
||||
- git fetch --tags
|
||||
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev uuid-dev
|
||||
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev
|
||||
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
|
||||
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock
|
||||
- sudo apt-get install -qq libqt4-dev
|
||||
- sudo apt-get install -qq libopenal-dev
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
|
||||
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
|
||||
- sudo mkdir /usr/src/gtest/build
|
||||
- cd /usr/src/gtest/build
|
||||
|
@ -37,3 +37,9 @@ notifications:
|
|||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#openmw"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
|
|
|
@ -4,10 +4,6 @@ if (APPLE)
|
|||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||
|
||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
endif (APPLE)
|
||||
|
||||
# Macros
|
||||
|
@ -20,7 +16,7 @@ include(OpenMWMacros)
|
|||
|
||||
include(GetGitRevisionDescription)
|
||||
|
||||
get_git_tag_revision(TAGHASH --tags --max-count=1)
|
||||
get_git_tag_revision(TAGHASH --tags --max-count=1 "HEAD...")
|
||||
get_git_head_revision(REFSPEC COMMITHASH)
|
||||
git_describe(VERSION --tags ${TAGHASH})
|
||||
|
||||
|
@ -206,10 +202,6 @@ if (MSVC10)
|
|||
set(PLATFORM_INCLUDE_DIR "")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
endif (APPLE)
|
||||
|
||||
# Dependencies
|
||||
|
||||
# Fix for not visible pthreads functions for linker with glibc 2.15
|
||||
|
@ -260,10 +252,15 @@ link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MY
|
|||
if (APPLE)
|
||||
# List used Ogre plugins
|
||||
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
|
||||
${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL}
|
||||
${OGRE_Plugin_CgProgramManager_LIBRARY_REL}
|
||||
${OGRE_Plugin_ParticleFX_LIBRARY_REL})
|
||||
|
||||
# Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's
|
||||
# not reliable and equals TRUE even if there's no Ogre Cg plugin
|
||||
if (Cg_FOUND)
|
||||
set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS}
|
||||
${OGRE_Plugin_CgProgramManager_LIBRARY_REL})
|
||||
endif ()
|
||||
|
||||
if (${OGRE_PLUGIN_DIR_REL}})
|
||||
set(OGRE_PLUGINS_REL_FOUND TRUE)
|
||||
endif ()
|
||||
|
@ -278,8 +275,6 @@ if (APPLE)
|
|||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
||||
endif ()
|
||||
|
||||
#set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
|
||||
"${APP_BUNDLE_DIR}/Contents/Info.plist")
|
||||
|
||||
|
@ -301,7 +296,8 @@ endif()
|
|||
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
|
||||
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
|
||||
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
|
||||
add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Plugins")
|
||||
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
|
||||
add_definitions(-DOGRE_PLUGIN_DIR="")
|
||||
else()
|
||||
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
|
||||
endif()
|
||||
|
@ -657,14 +653,14 @@ if (APPLE)
|
|||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||
|
||||
set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
||||
|
||||
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/OpenCS.app")
|
||||
set(OPENCS_BUNDLE_NAME "OpenCS.app")
|
||||
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
||||
|
||||
set(PLUGINS "")
|
||||
set(ABSOLUTE_PLUGINS "")
|
||||
|
||||
foreach (PLUGIN ${USED_OGRE_PLUGINS})
|
||||
|
@ -672,12 +668,36 @@ if (APPLE)
|
|||
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
|
||||
endforeach ()
|
||||
|
||||
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins")
|
||||
install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime)
|
||||
foreach (PLUGIN ${ABSOLUTE_PLUGINS})
|
||||
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME)
|
||||
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
|
||||
endforeach ()
|
||||
install(CODE "
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
include(BundleUtilities)
|
||||
" COMPONENT Runtime)
|
||||
|
||||
# installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX})
|
||||
# and returns list of install paths for all installed plugins
|
||||
function (install_plugins_for_bundle bundle_path plugins_var)
|
||||
set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks")
|
||||
|
||||
set(PLUGINS "")
|
||||
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}")
|
||||
|
||||
foreach (PLUGIN ${ABSOLUTE_PLUGINS})
|
||||
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME)
|
||||
get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE)
|
||||
|
||||
set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}")
|
||||
set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}")
|
||||
|
||||
install(CODE "
|
||||
copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\")
|
||||
" COMPONENT Runtime)
|
||||
endforeach ()
|
||||
|
||||
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
|
||||
endfunction (install_plugins_for_bundle)
|
||||
|
||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
|
||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
||||
|
||||
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
|
||||
set(DIRS "")
|
||||
|
@ -690,6 +710,7 @@ if (APPLE)
|
|||
# Current limitations:
|
||||
# 1. Handles only frameworks, not simple libs
|
||||
INSTALL(CODE "
|
||||
cmake_policy(SET CMP0009 OLD)
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
|
||||
|
@ -721,11 +742,8 @@ if (APPLE)
|
|||
endif()
|
||||
endfunction(gp_resolve_item_override)
|
||||
|
||||
cmake_policy(SET CMP0009 OLD)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
|
||||
fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\")
|
||||
fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\")
|
||||
" COMPONENT Runtime)
|
||||
include(CPack)
|
||||
endif (APPLE)
|
||||
|
|
|
@ -38,7 +38,7 @@ opencs_units (model/tools
|
|||
|
||||
opencs_units_noqt (model/tools
|
||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||
birthsigncheck spellcheck referenceablecheck
|
||||
birthsigncheck spellcheck referenceablecheck scriptcheck
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -210,6 +210,8 @@ int CS::Editor::run()
|
|||
if (mLocal.empty())
|
||||
return 1;
|
||||
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
// TODO: setting
|
||||
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
|
||||
|
||||
|
@ -221,8 +223,12 @@ int CS::Editor::run()
|
|||
params.insert(std::make_pair("FSAA", "0"));
|
||||
params.insert(std::make_pair("vsync", "false"));
|
||||
params.insert(std::make_pair("hidden", "true"));
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
params.insert(std::make_pair("macAPI", "cocoa"));
|
||||
#endif
|
||||
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
||||
hiddenWindow->setActive(false);
|
||||
#endif
|
||||
|
||||
mStartup.show();
|
||||
|
||||
|
|
|
@ -44,8 +44,11 @@ int main(int argc, char *argv[])
|
|||
// SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
|
||||
|
||||
Application mApplication (argc, argv);
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
OgreInit::OgreInit ogreInit;
|
||||
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
|
|
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
|
||||
#include "scriptcheck.hpp"
|
||||
|
||||
#include <components/compiler/tokenloc.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
#include <components/compiler/fileparser.hpp>
|
||||
#include <components/compiler/exception.hpp>
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include "../world/data.hpp"
|
||||
|
||||
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
|
||||
Type type)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|";
|
||||
|
||||
if (type==ErrorMessage)
|
||||
stream << "error ";
|
||||
else
|
||||
stream << "warning ";
|
||||
|
||||
stream
|
||||
<< "script " << mFile
|
||||
<< ", line " << loc.mLine << ", column " << loc.mColumn
|
||||
<< " (" << loc.mLiteral << "): " << message;
|
||||
|
||||
mMessages->push_back (stream.str());
|
||||
}
|
||||
|
||||
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|";
|
||||
|
||||
if (type==ErrorMessage)
|
||||
stream << "error: ";
|
||||
else
|
||||
stream << "warning: ";
|
||||
|
||||
stream << message;
|
||||
|
||||
mMessages->push_back (stream.str());
|
||||
}
|
||||
|
||||
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data)
|
||||
: mData (data), mContext (data), mMessages (0)
|
||||
{
|
||||
/// \todo add an option to configure warning mode
|
||||
setWarningsMode (0);
|
||||
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
mContext.setExtensions (&mExtensions);
|
||||
}
|
||||
|
||||
int CSMTools::ScriptCheckStage::setup()
|
||||
{
|
||||
mContext.clear();
|
||||
mMessages = 0;
|
||||
mId.clear();
|
||||
|
||||
return mData.getScripts().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mMessages = &messages;
|
||||
mId = mData.getScripts().getId (stage);
|
||||
|
||||
try
|
||||
{
|
||||
mFile = mData.getScripts().getRecord (stage).get().mId;
|
||||
std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText);
|
||||
|
||||
Compiler::Scanner scanner (*this, input, mContext.getExtensions());
|
||||
|
||||
Compiler::FileParser parser (*this, mContext);
|
||||
|
||||
scanner.scan (parser);
|
||||
}
|
||||
catch (const Compiler::SourceException&)
|
||||
{
|
||||
// error has already been reported via error handler
|
||||
}
|
||||
catch (const std::exception& error)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|Critical compile error: " << error.what();
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
mMessages = 0;
|
||||
}
|
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef CSM_TOOLS_SCRIPTCHECK_H
|
||||
#define CSM_TOOLS_SCRIPTCHECK_H
|
||||
|
||||
#include <components/compiler/errorhandler.hpp>
|
||||
#include <components/compiler/extensions.hpp>
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
#include "../world/scriptcontext.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that scripts compile
|
||||
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
|
||||
{
|
||||
const CSMWorld::Data& mData;
|
||||
Compiler::Extensions mExtensions;
|
||||
CSMWorld::ScriptContext mContext;
|
||||
std::string mId;
|
||||
std::string mFile;
|
||||
std::vector<std::string> *mMessages;
|
||||
|
||||
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
|
||||
///< Report error to the user.
|
||||
|
||||
virtual void report (const std::string& message, Type type);
|
||||
///< Report a file related error
|
||||
|
||||
public:
|
||||
|
||||
ScriptCheckStage (const CSMWorld::Data& data);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@
|
|||
#include "birthsigncheck.hpp"
|
||||
#include "spellcheck.hpp"
|
||||
#include "referenceablecheck.hpp"
|
||||
#include "scriptcheck.hpp"
|
||||
|
||||
CSMDoc::Operation *CSMTools::Tools::get (int type)
|
||||
{
|
||||
|
@ -77,6 +78,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
|
|||
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
|
||||
|
||||
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
|
||||
|
||||
mVerifier->appendStage (new ScriptCheckStage (mData));
|
||||
}
|
||||
|
||||
return mVerifier;
|
||||
|
|
|
@ -33,7 +33,9 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI
|
|||
|
||||
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
|
||||
: QSortFilterProxyModel (parent)
|
||||
{}
|
||||
{
|
||||
setSortCaseSensitivity (Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
|
||||
{
|
||||
|
|
|
@ -432,7 +432,7 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count)
|
|||
|
||||
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
|
||||
{
|
||||
mData.appendRecord (type, id);
|
||||
mData.appendRecord (type, id, false);
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::searchId (const std::string& id) const
|
||||
|
@ -450,7 +450,7 @@ void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record)
|
|||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
|
||||
void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
const CSMWorld::UniversalId::Type type)
|
||||
{
|
||||
|
@ -467,7 +467,7 @@ void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
|||
|
||||
int index = mData.getAppendIndex (type);
|
||||
|
||||
mData.appendRecord (type, id);
|
||||
mData.appendRecord (type, id, false);
|
||||
|
||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers
|
|||
{
|
||||
// new record
|
||||
int index = mData.getAppendIndex (type);
|
||||
mData.appendRecord (type, id);
|
||||
mData.appendRecord (type, id, base);
|
||||
|
||||
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index)
|
|||
return iter->second->getRecord (index.first);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id)
|
||||
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id, bool base)
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||
mRecordContainers.find (type);
|
||||
|
@ -139,7 +139,7 @@ void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::strin
|
|||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
iter->second->appendRecord (id);
|
||||
iter->second->appendRecord (id, base);
|
||||
|
||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
||||
LocalIndex (iter->second->getSize()-1, type)));
|
||||
|
|
|
@ -45,8 +45,8 @@ namespace CSMWorld
|
|||
|
||||
virtual RecordBase& getRecord (int index)= 0;
|
||||
|
||||
virtual void appendRecord (const std::string& id) = 0;
|
||||
|
||||
virtual void appendRecord (const std::string& id, bool base) = 0;
|
||||
|
||||
virtual void insertRecord (RecordBase& record) = 0;
|
||||
|
||||
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
|
||||
|
@ -69,8 +69,8 @@ namespace CSMWorld
|
|||
|
||||
virtual RecordBase& getRecord (int index);
|
||||
|
||||
virtual void appendRecord (const std::string& id);
|
||||
|
||||
virtual void appendRecord (const std::string& id, bool base);
|
||||
|
||||
virtual void insertRecord (RecordBase& record);
|
||||
|
||||
virtual void load (int index, ESM::ESMReader& reader, bool base);
|
||||
|
@ -88,7 +88,7 @@ namespace CSMWorld
|
|||
Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record);
|
||||
mContainer.push_back(newRecord);
|
||||
}
|
||||
|
||||
|
||||
template<typename RecordT>
|
||||
int RefIdDataContainer<RecordT>::getSize() const
|
||||
{
|
||||
|
@ -108,12 +108,15 @@ namespace CSMWorld
|
|||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id)
|
||||
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base)
|
||||
{
|
||||
Record<RecordT> record;
|
||||
|
||||
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||
|
||||
record.mBase.mId = id;
|
||||
record.mModified.mId = id;
|
||||
record.mModified.blank();
|
||||
record.mState = RecordBase::State_ModifiedOnly;
|
||||
(base ? record.mBase : record.mModified).blank();
|
||||
|
||||
mContainer.push_back (record);
|
||||
}
|
||||
|
@ -206,14 +209,14 @@ namespace CSMWorld
|
|||
LocalIndex searchId (const std::string& id) const;
|
||||
|
||||
void erase (int index, int count);
|
||||
|
||||
|
||||
void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id);
|
||||
|
||||
const RecordBase& getRecord (const LocalIndex& index) const;
|
||||
|
||||
RecordBase& getRecord (const LocalIndex& index);
|
||||
|
||||
void appendRecord (UniversalId::Type type, const std::string& id);
|
||||
void appendRecord (UniversalId::Type type, const std::string& id, bool base);
|
||||
|
||||
int getAppendIndex (UniversalId::Type type) const;
|
||||
|
||||
|
|
|
@ -5,23 +5,92 @@
|
|||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/compiler/quickfileparser.hpp>
|
||||
#include <components/compiler/nullerrorhandler.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
|
||||
#include "data.hpp"
|
||||
|
||||
CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
|
||||
|
||||
bool CSMWorld::ScriptContext::canDeclareLocals() const
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
|
||||
{
|
||||
int index = mData.getGlobals().searchId (name);
|
||||
|
||||
if (index!=-1)
|
||||
{
|
||||
switch (mData.getGlobals().getRecord (index).get().mValue.getType())
|
||||
{
|
||||
case ESM::VT_Short: return 's';
|
||||
case ESM::VT_Long: return 'l';
|
||||
case ESM::VT_Float: return 'f';
|
||||
|
||||
default: return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const
|
||||
std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
|
||||
const std::string& id) const
|
||||
{
|
||||
return ' ';
|
||||
/// \todo invalidate locals cache on change to scripts
|
||||
|
||||
std::string id2 = Misc::StringUtils::lowerCase (id);
|
||||
|
||||
int index = mData.getScripts().searchId (id2);
|
||||
bool reference = false;
|
||||
|
||||
if (index!=-1)
|
||||
{
|
||||
// ID is not a script ID. Search for a matching referenceable instead.
|
||||
index = mData.getReferenceables().searchId (id2);
|
||||
|
||||
if (index!=-1)
|
||||
{
|
||||
// Referenceable found.
|
||||
int columnIndex = mData.getReferenceables().searchColumnIndex (Columns::ColumnId_Script);
|
||||
|
||||
if (columnIndex!=-1)
|
||||
{
|
||||
id2 = Misc::StringUtils::lowerCase (mData.getReferenceables().
|
||||
getData (index, columnIndex).toString().toUtf8().constData());
|
||||
|
||||
if (!id2.empty())
|
||||
{
|
||||
// Referenceable has a script -> use it.
|
||||
index = mData.getScripts().searchId (id2);
|
||||
reference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index==-1)
|
||||
return std::make_pair (' ', false);
|
||||
|
||||
std::map<std::string, Compiler::Locals>::iterator iter = mLocals.find (id2);
|
||||
|
||||
if (iter==mLocals.end())
|
||||
{
|
||||
Compiler::Locals locals;
|
||||
|
||||
Compiler::NullErrorHandler errorHandler;
|
||||
std::istringstream stream (mData.getScripts().getRecord (index).get().mScriptText);
|
||||
Compiler::QuickFileParser parser (errorHandler, *this, locals);
|
||||
Compiler::Scanner scanner (errorHandler, stream, getExtensions());
|
||||
scanner.scan (parser);
|
||||
|
||||
iter = mLocals.insert (std::make_pair (id2, locals)).first;
|
||||
}
|
||||
|
||||
return std::make_pair (iter->second.getType (Misc::StringUtils::lowerCase (name)), reference);
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
||||
|
@ -31,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
|||
mIds = mData.getIds();
|
||||
|
||||
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
|
||||
std::sort (mIds.begin(), mIds.end());
|
||||
|
||||
mIdsUpdated = true;
|
||||
}
|
||||
|
@ -38,7 +108,19 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
|||
return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name));
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const
|
||||
{
|
||||
return mData.getJournals().searchId (name)!=-1;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::invalidateIds()
|
||||
{
|
||||
mIdsUpdated = false;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::clear()
|
||||
{
|
||||
mIds.clear();
|
||||
mIdsUpdated = false;
|
||||
mLocals.clear();
|
||||
}
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/compiler/context.hpp>
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -15,6 +17,7 @@ namespace CSMWorld
|
|||
const Data& mData;
|
||||
mutable std::vector<std::string> mIds;
|
||||
mutable bool mIdsUpdated;
|
||||
mutable std::map<std::string, Compiler::Locals> mLocals;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -26,13 +29,23 @@ namespace CSMWorld
|
|||
virtual char getGlobalType (const std::string& name) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual std::pair<char, bool> getMemberType (const std::string& name,
|
||||
const std::string& id) const;
|
||||
///< Return type of member variable \a name in script \a id or in script of reference of
|
||||
/// \a id
|
||||
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
/// second: true: script of reference
|
||||
|
||||
virtual bool isId (const std::string& name) const;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
virtual bool isJournalId (const std::string& name) const;
|
||||
///< Does \a name match a journal ID?
|
||||
|
||||
void invalidateIds();
|
||||
|
||||
void clear();
|
||||
///< Remove all cached data.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,10 @@ namespace CSVRender
|
|||
params.insert(std::make_pair("title", windowTitle.str()));
|
||||
params.insert(std::make_pair("FSAA", "0")); // TODO setting
|
||||
params.insert(std::make_pair("vsync", "false")); // TODO setting
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
params.insert(std::make_pair("macAPI", "cocoa"));
|
||||
params.insert(std::make_pair("macAPICocoaUseNSView", "true"));
|
||||
#endif
|
||||
|
||||
mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, ¶ms);
|
||||
mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1));
|
||||
|
|
|
@ -43,12 +43,26 @@ toolbar->addTool (new SceneToolMode (toolbar));
|
|||
toolbar->addTool (new SceneToolMode (toolbar));
|
||||
layout2->addWidget (toolbar, 0);
|
||||
|
||||
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
|
||||
|
||||
layout2->addWidget (sceneWidget, 1);
|
||||
|
||||
layout->insertLayout (0, layout2, 1);
|
||||
#endif
|
||||
/// \todo replace with rendering widget
|
||||
QPalette palette2 (palette());
|
||||
palette2.setColor (QPalette::Background, Qt::white);
|
||||
QLabel *placeholder = new QLabel ("Here goes the 3D scene", this);
|
||||
placeholder->setAutoFillBackground (true);
|
||||
placeholder->setPalette (palette2);
|
||||
placeholder->setAlignment (Qt::AlignHCenter);
|
||||
|
||||
layout2->addWidget (placeholder, 1);
|
||||
|
||||
layout->insertLayout (0, layout2, 1);
|
||||
|
||||
|
||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QString>
|
||||
#include <qt4/QtCore/qnamespace.h>
|
||||
#include <QtCore/qnamespace.h>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
|
|
|
@ -155,6 +155,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
, mSkipMenu (false)
|
||||
, mUseSound (true)
|
||||
, mCompileAll (false)
|
||||
, mWarningsMode (1)
|
||||
, mScriptContext (0)
|
||||
, mFSStrict (false)
|
||||
, mScriptConsoleMode (false)
|
||||
|
@ -424,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mScriptContext->setExtensions (&mExtensions);
|
||||
|
||||
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
|
||||
mVerboseScripts, *mScriptContext));
|
||||
mVerboseScripts, *mScriptContext, mWarningsMode));
|
||||
|
||||
// Create game mechanics system
|
||||
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
|
||||
|
@ -612,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path)
|
|||
mStartupScript = path;
|
||||
}
|
||||
|
||||
|
||||
void OMW::Engine::setActivationDistanceOverride (int distance)
|
||||
{
|
||||
mActivationDistanceOverride = distance;
|
||||
}
|
||||
|
||||
void OMW::Engine::setWarningsMode (int mode)
|
||||
{
|
||||
mWarningsMode = mode;
|
||||
}
|
|
@ -74,6 +74,7 @@ namespace OMW
|
|||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
int mWarningsMode;
|
||||
std::string mFocusName;
|
||||
std::map<std::string,std::string> mFallbackMap;
|
||||
bool mScriptConsoleMode;
|
||||
|
@ -181,6 +182,8 @@ namespace OMW
|
|||
/// Override the game setting specified activation distance.
|
||||
void setActivationDistanceOverride (int distance);
|
||||
|
||||
void setWarningsMode (int mode);
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
|
|
|
@ -136,6 +136,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("script-run", bpo::value<std::string>()->default_value(""),
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("script-warn", bpo::value<int>()->implicit_value (1)
|
||||
->default_value (1),
|
||||
"handling of warnings when compiling scripts\n"
|
||||
"\t0 - ignore warning\n"
|
||||
"\t1 - show warning but consider script as correctly compiled anyway\n"
|
||||
"\t2 - treat warnings as errors")
|
||||
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
|
@ -241,6 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
||||
engine.setStartupScript (variables["script-run"].as<std::string>());
|
||||
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
|
||||
engine.setWarningsMode (variables["script-warn"].as<int>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
|
@ -52,6 +60,12 @@ namespace MWBase
|
|||
virtual void persuade (int type) = 0;
|
||||
virtual int getTemporaryDispositionChange () const = 0;
|
||||
virtual void applyDispositionChange (int delta) = 0;
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -766,8 +766,11 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
readState (state2.mInventory);
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mContainerStore->readState (state2.mInventory);
|
||||
customData.mCreatureStats.readState (state2.mCreatureStats);
|
||||
|
||||
}
|
||||
|
||||
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
|
@ -777,8 +780,10 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
writeState (state2.mInventory);
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mContainerStore->writeState (state2.mInventory);
|
||||
customData.mCreatureStats.writeState (state2.mCreatureStats);
|
||||
}
|
||||
|
||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||
|
|
|
@ -115,21 +115,11 @@ namespace MWClass
|
|||
|
||||
if (ref->mRef.mTeleport)
|
||||
{
|
||||
// teleport door
|
||||
/// \todo remove this if clause once ActionTeleport can also support other actors
|
||||
if (MWBase::Environment::get().getWorld()->getPlayerPtr()==actor)
|
||||
{
|
||||
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest));
|
||||
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest));
|
||||
|
||||
action->setSound(openSound);
|
||||
action->setSound(openSound);
|
||||
|
||||
return action;
|
||||
}
|
||||
else
|
||||
{
|
||||
// another NPC or a creature is using the door
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1278,8 +1278,11 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
readState (state2.mInventory);
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mInventoryStore.readState (state2.mInventory);
|
||||
customData.mNpcStats.readState (state2.mNpcStats);
|
||||
static_cast<MWMechanics::CreatureStats&> (customData.mNpcStats).readState (state2.mCreatureStats);
|
||||
}
|
||||
|
||||
void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
|
@ -1289,8 +1292,11 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
writeState (state2.mInventory);
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mInventoryStore.writeState (state2.mInventory);
|
||||
customData.mNpcStats.writeState (state2.mNpcStats);
|
||||
static_cast<const MWMechanics::CreatureStats&> (customData.mNpcStats).writeState (state2.mCreatureStats);
|
||||
}
|
||||
|
||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <components/esm/loaddial.hpp>
|
||||
#include <components/esm/loadinfo.hpp>
|
||||
#include <components/esm/dialoguestate.hpp>
|
||||
|
||||
#include <components/compiler/exception.hpp>
|
||||
#include <components/compiler/errorhandler.hpp>
|
||||
|
@ -591,6 +592,41 @@ namespace MWDialogue
|
|||
}
|
||||
}
|
||||
|
||||
int DialogueManager::countSavedGameRecords() const
|
||||
{
|
||||
return 1; // known topics
|
||||
}
|
||||
|
||||
void DialogueManager::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
ESM::DialogueState state;
|
||||
|
||||
for (std::map<std::string, bool>::const_iterator iter (mKnownTopics.begin());
|
||||
iter!=mKnownTopics.end(); ++iter)
|
||||
if (iter->second)
|
||||
state.mKnownTopics.push_back (iter->first);
|
||||
|
||||
writer.startRecord (ESM::REC_DIAS);
|
||||
state.save (writer);
|
||||
writer.endRecord (ESM::REC_DIAS);
|
||||
}
|
||||
|
||||
void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_DIAS)
|
||||
{
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
ESM::DialogueState state;
|
||||
state.load (reader);
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (state.mKnownTopics.begin());
|
||||
iter!=state.mKnownTopics.end(); ++iter)
|
||||
if (store.get<ESM::Dialogue>().search (*iter))
|
||||
mKnownTopics.insert (std::make_pair (*iter, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
|
||||
{
|
||||
|
|
|
@ -78,6 +78,12 @@ namespace MWDialogue
|
|||
virtual void persuade (int type);
|
||||
virtual int getTemporaryDispositionChange () const;
|
||||
virtual void applyDispositionChange (int delta);
|
||||
|
||||
virtual int countSavedGameRecords() const;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
@ -647,7 +648,9 @@ namespace MWInput
|
|||
return;
|
||||
|
||||
// Not allowed if no spell selected
|
||||
if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty())
|
||||
MWWorld::InventoryStore& inventory = MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer());
|
||||
if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() &&
|
||||
inventory.getSelectedEnchantItem() == inventory.end())
|
||||
return;
|
||||
|
||||
MWMechanics::DrawState_ state = mPlayer->getDrawState();
|
||||
|
|
|
@ -1,8 +1,27 @@
|
|||
#include "aiactivate.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/action.hpp"
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiActivate::AiActivate(const std::string &objectId)
|
||||
: mObjectId(objectId)
|
||||
: mObjectId(objectId)
|
||||
{
|
||||
}
|
||||
MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
||||
|
@ -11,8 +30,81 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
|||
}
|
||||
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
std::cout << "AiActivate completed.\n";
|
||||
return true;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
||||
const ESM::Cell *cell = actor.getCell()->mCell;
|
||||
|
||||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
if(cell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(cell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
{
|
||||
movement.mPosition[1] = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(cell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(cell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
{
|
||||
movement.mPosition[1] = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
||||
ESM::Position targetPos = target.getRefData().getPosition();
|
||||
|
||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
mCellX = cell->mData.mX;
|
||||
mCellY = cell->mData.mY;
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = targetPos.pos[0];
|
||||
dest.mY = targetPos.pos[1];
|
||||
dest.mZ = targetPos.pos[2];
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||
}
|
||||
|
||||
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
|
||||
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
|
||||
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200)
|
||||
{
|
||||
movement.mPosition[1] = 0;
|
||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
movement.mPosition[1] = 0;
|
||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
||||
return true;
|
||||
}
|
||||
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
zTurn(actor, Ogre::Degree(zAngle));
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
movement.mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiActivate::getTypeId() const
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "aipackage.hpp"
|
||||
#include <string>
|
||||
|
||||
#include "pathfinding.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
|
@ -18,6 +20,10 @@ namespace MWMechanics
|
|||
|
||||
private:
|
||||
std::string mObjectId;
|
||||
|
||||
PathFinder mPathFinder;
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
}
|
||||
#endif // GAME_MWMECHANICS_AIACTIVATE_H
|
||||
|
|
|
@ -21,8 +21,8 @@ namespace MWMechanics
|
|||
{
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
, cellX(std::numeric_limits<int>::max())
|
||||
, cellY(std::numeric_limits<int>::max())
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -62,11 +62,11 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY;
|
||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = cell->mData.mX;
|
||||
cellY = cell->mData.mY;
|
||||
mCellX = cell->mData.mX;
|
||||
mCellY = cell->mData.mY;
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = mX;
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace MWMechanics
|
|||
float mY;
|
||||
float mZ;
|
||||
|
||||
int cellX;
|
||||
int cellY;
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
|
||||
PathFinder mPathFinder;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/esm/creaturestats.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -457,4 +459,21 @@ namespace MWMechanics
|
|||
mAttackStrength = value;
|
||||
}
|
||||
|
||||
void CreatureStats::writeState (ESM::CreatureStats& state) const
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
mAttributes[i].writeState (state.mAttributes[i]);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].writeState (state.mDynamic[i]);
|
||||
}
|
||||
|
||||
void CreatureStats::readState (const ESM::CreatureStats& state)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
mAttributes[i].readState (state.mAttributes[i]);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].readState (state.mDynamic[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include "aisequence.hpp"
|
||||
#include "drawstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct CreatureStats;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
/// \brief Common creature stats
|
||||
|
@ -212,6 +217,10 @@ namespace MWMechanics
|
|||
std::set<int> mBoundItems;
|
||||
// Same as above
|
||||
std::map<int, std::string> mSummonedCreatures;
|
||||
|
||||
void writeState (ESM::CreatureStats& state) const;
|
||||
|
||||
void readState (const ESM::CreatureStats& state);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <components/esm/loadclas.hpp>
|
||||
#include <components/esm/loadgmst.hpp>
|
||||
#include <components/esm/loadfact.hpp>
|
||||
#include <components/esm/npcstats.hpp>
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
@ -423,3 +424,89 @@ void MWMechanics::NpcStats::setTimeToStartDrowning(float time)
|
|||
assert(time>=0 && time<=20);
|
||||
mTimeToStartDrowning=time;
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
|
||||
{
|
||||
for (std::map<std::string, int>::const_iterator iter (mFactionRank.begin());
|
||||
iter!=mFactionRank.end(); ++iter)
|
||||
state.mFactions[iter->first].mRank = iter->second;
|
||||
|
||||
state.mDisposition = mDisposition;
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
{
|
||||
mSkill[i].writeState (state.mSkills[i].mRegular);
|
||||
mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf);
|
||||
}
|
||||
|
||||
state.mBounty = mBounty;
|
||||
|
||||
for (std::set<std::string>::const_iterator iter (mExpelled.begin());
|
||||
iter!=mExpelled.end(); ++iter)
|
||||
state.mFactions[*iter].mExpelled = true;
|
||||
|
||||
for (std::map<std::string, int>::const_iterator iter (mFactionReputation.begin());
|
||||
iter!=mFactionReputation.end(); ++iter)
|
||||
state.mFactions[iter->first].mReputation = iter->second;
|
||||
|
||||
state.mReputation = mReputation;
|
||||
state.mWerewolfKills = mWerewolfKills;
|
||||
state.mProfit = mProfit;
|
||||
state.mAttackStrength = mAttackStrength;
|
||||
state.mLevelProgress = mLevelProgress;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
state.mSkillIncrease[i] = mSkillIncreases[i];
|
||||
|
||||
std::copy (mUsedIds.begin(), mUsedIds.end(), std::back_inserter (state.mUsedIds));
|
||||
|
||||
state.mTimeToStartDrowning = mTimeToStartDrowning;
|
||||
state.mLastDrowningHit = mLastDrowningHit;
|
||||
state.mLevelHealthBonus = mLevelHealthBonus;
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
|
||||
{
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
for (std::map<std::string, ESM::NpcStats::Faction>::const_iterator iter (state.mFactions.begin());
|
||||
iter!=state.mFactions.end(); ++iter)
|
||||
if (store.get<ESM::Faction>().search (iter->first))
|
||||
{
|
||||
if (iter->second.mExpelled)
|
||||
mExpelled.insert (iter->first);
|
||||
|
||||
if (iter->second.mRank)
|
||||
mFactionRank.insert (std::make_pair (iter->first, iter->second.mRank));
|
||||
|
||||
if (iter->second.mReputation)
|
||||
mFactionReputation.insert (std::make_pair (iter->first, iter->second.mReputation));
|
||||
}
|
||||
|
||||
mDisposition = state.mDisposition;
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
{
|
||||
mSkill[i].readState (state.mSkills[i].mRegular);
|
||||
mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf);
|
||||
}
|
||||
|
||||
mBounty = state.mBounty;
|
||||
mReputation = state.mReputation;
|
||||
mWerewolfKills = state.mWerewolfKills;
|
||||
mProfit = state.mProfit;
|
||||
mAttackStrength = state.mAttackStrength;
|
||||
mLevelProgress = state.mLevelProgress;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
mSkillIncreases[i] = state.mSkillIncrease[i];
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (state.mUsedIds.begin());
|
||||
iter!=state.mUsedIds.end(); ++iter)
|
||||
if (store.find (*iter))
|
||||
mUsedIds.insert (*iter);
|
||||
|
||||
mTimeToStartDrowning = state.mTimeToStartDrowning;
|
||||
mLastDrowningHit = state.mLastDrowningHit;
|
||||
mLevelHealthBonus = state.mLevelHealthBonus;
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
namespace ESM
|
||||
{
|
||||
struct Class;
|
||||
struct NpcStats;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -128,6 +129,10 @@ namespace MWMechanics
|
|||
/// Sets time left for the creature to drown if it stays underwater.
|
||||
/// @param time value from [0,20]
|
||||
void setTimeToStartDrowning(float time);
|
||||
|
||||
void writeState (ESM::NpcStats& state) const;
|
||||
|
||||
void readState (const ESM::NpcStats& state);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
29
apps/openmw/mwmechanics/stat.cpp
Normal file
29
apps/openmw/mwmechanics/stat.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
#include "stat.hpp"
|
||||
|
||||
void MWMechanics::AttributeValue::writeState (ESM::StatState<int>& state) const
|
||||
{
|
||||
state.mBase = mBase;
|
||||
state.mMod = mModifier;
|
||||
state.mDamage = mDamage;
|
||||
}
|
||||
|
||||
void MWMechanics::AttributeValue::readState (const ESM::StatState<int>& state)
|
||||
{
|
||||
mBase = state.mBase;
|
||||
mModifier = state.mMod;
|
||||
mDamage = state.mDamage;
|
||||
}
|
||||
|
||||
|
||||
void MWMechanics::SkillValue::writeState (ESM::StatState<int>& state) const
|
||||
{
|
||||
AttributeValue::writeState (state);
|
||||
state.mProgress = mProgress;
|
||||
}
|
||||
|
||||
void MWMechanics::SkillValue::readState (const ESM::StatState<int>& state)
|
||||
{
|
||||
AttributeValue::readState (state);
|
||||
mProgress = state.mProgress;
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <limits>
|
||||
|
||||
#include <components/esm/statstate.hpp>
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
template<typename T>
|
||||
|
@ -86,6 +88,18 @@ namespace MWMechanics
|
|||
{
|
||||
mModified = mBase + modifier;
|
||||
}
|
||||
|
||||
void writeState (ESM::StatState<T>& state) const
|
||||
{
|
||||
state.mBase = mBase;
|
||||
state.mMod = mModified;
|
||||
}
|
||||
|
||||
void readState (const ESM::StatState<T>& state)
|
||||
{
|
||||
mBase = state.mBase;
|
||||
mModified = state.mMod;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -190,6 +204,18 @@ namespace MWMechanics
|
|||
mStatic.setModifier (modifier);
|
||||
setCurrent (getCurrent()+diff);
|
||||
}
|
||||
|
||||
void writeState (ESM::StatState<T>& state) const
|
||||
{
|
||||
mStatic.writeState (state);
|
||||
state.mCurrent = mCurrent;
|
||||
}
|
||||
|
||||
void readState (const ESM::StatState<T>& state)
|
||||
{
|
||||
mStatic.readState (state);
|
||||
mCurrent = state.mCurrent;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -225,6 +251,10 @@ namespace MWMechanics
|
|||
void damage(int damage) { mDamage += damage; }
|
||||
void restore(int amount) { mDamage -= std::min(mDamage, amount); }
|
||||
int getDamage() const { return mDamage; }
|
||||
|
||||
void writeState (ESM::StatState<int>& state) const;
|
||||
|
||||
void readState (const ESM::StatState<int>& state);
|
||||
};
|
||||
|
||||
class SkillValue : public AttributeValue
|
||||
|
@ -234,6 +264,10 @@ namespace MWMechanics
|
|||
SkillValue() : mProgress(0) {}
|
||||
float getProgress() const { return mProgress; }
|
||||
void setProgress(float progress) { mProgress = progress; }
|
||||
|
||||
void writeState (ESM::StatState<int>& state) const;
|
||||
|
||||
void readState (const ESM::StatState<int>& state);
|
||||
};
|
||||
|
||||
inline bool operator== (const AttributeValue& left, const AttributeValue& right)
|
||||
|
|
|
@ -697,7 +697,8 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
|||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
||||
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
||||
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
#include "terrainstorage.hpp"
|
||||
|
||||
#include <OgreVector2.h>
|
||||
#include <OgreTextureManager.h>
|
||||
#include <OgreStringConverter.h>
|
||||
#include <OgreRenderSystem.h>
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
@ -53,4 +62,509 @@ namespace MWRender
|
|||
return esmStore.get<ESM::LandTexture>().find(index, plugin);
|
||||
}
|
||||
|
||||
bool TerrainStorage::getMinMaxHeights(float size, const Ogre::Vector2 ¢er, float &min, float &max)
|
||||
{
|
||||
assert (size <= 1 && "TerrainStorage::getMinMaxHeights, chunk size should be <= 1 cell");
|
||||
|
||||
/// \todo investigate if min/max heights should be stored at load time in ESM::Land instead
|
||||
|
||||
Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f);
|
||||
|
||||
assert(origin.x == (int) origin.x);
|
||||
assert(origin.y == (int) origin.y);
|
||||
|
||||
int cellX = origin.x;
|
||||
int cellY = origin.y;
|
||||
|
||||
const ESM::Land* land = getLand(cellX, cellY);
|
||||
if (!land)
|
||||
return false;
|
||||
|
||||
min = std::numeric_limits<float>().max();
|
||||
max = -std::numeric_limits<float>().max();
|
||||
for (int row=0; row<ESM::Land::LAND_SIZE; ++row)
|
||||
{
|
||||
for (int col=0; col<ESM::Land::LAND_SIZE; ++col)
|
||||
{
|
||||
float h = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row];
|
||||
if (h > max)
|
||||
max = h;
|
||||
if (h < min)
|
||||
min = h;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TerrainStorage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row)
|
||||
{
|
||||
while (col >= ESM::Land::LAND_SIZE-1)
|
||||
{
|
||||
++cellY;
|
||||
col -= ESM::Land::LAND_SIZE-1;
|
||||
}
|
||||
while (row >= ESM::Land::LAND_SIZE-1)
|
||||
{
|
||||
++cellX;
|
||||
row -= ESM::Land::LAND_SIZE-1;
|
||||
}
|
||||
while (col < 0)
|
||||
{
|
||||
--cellY;
|
||||
col += ESM::Land::LAND_SIZE-1;
|
||||
}
|
||||
while (row < 0)
|
||||
{
|
||||
--cellX;
|
||||
row += ESM::Land::LAND_SIZE-1;
|
||||
}
|
||||
ESM::Land* land = getLand(cellX, cellY);
|
||||
if (land && land->mHasData)
|
||||
{
|
||||
normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
|
||||
normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
|
||||
normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
|
||||
normal.normalise();
|
||||
}
|
||||
else
|
||||
normal = Ogre::Vector3(0,0,1);
|
||||
}
|
||||
|
||||
void TerrainStorage::averageNormal(Ogre::Vector3 &normal, int cellX, int cellY, int col, int row)
|
||||
{
|
||||
Ogre::Vector3 n1,n2,n3,n4;
|
||||
fixNormal(n1, cellX, cellY, col+1, row);
|
||||
fixNormal(n2, cellX, cellY, col-1, row);
|
||||
fixNormal(n3, cellX, cellY, col, row+1);
|
||||
fixNormal(n4, cellX, cellY, col, row-1);
|
||||
normal = (n1+n2+n3+n4);
|
||||
normal.normalise();
|
||||
}
|
||||
|
||||
void TerrainStorage::fixColour (Ogre::ColourValue& color, int cellX, int cellY, int col, int row)
|
||||
{
|
||||
if (col == ESM::Land::LAND_SIZE-1)
|
||||
{
|
||||
++cellY;
|
||||
col = 0;
|
||||
}
|
||||
if (row == ESM::Land::LAND_SIZE-1)
|
||||
{
|
||||
++cellX;
|
||||
row = 0;
|
||||
}
|
||||
ESM::Land* land = getLand(cellX, cellY);
|
||||
if (land && land->mLandData->mUsingColours)
|
||||
{
|
||||
color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f;
|
||||
color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f;
|
||||
color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
color.r = 1;
|
||||
color.g = 1;
|
||||
color.b = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
|
||||
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
|
||||
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
|
||||
Ogre::HardwareVertexBufferSharedPtr colourBuffer)
|
||||
{
|
||||
// LOD level n means every 2^n-th vertex is kept
|
||||
size_t increment = 1 << lodLevel;
|
||||
|
||||
Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f);
|
||||
assert(origin.x == (int) origin.x);
|
||||
assert(origin.y == (int) origin.y);
|
||||
|
||||
int startX = origin.x;
|
||||
int startY = origin.y;
|
||||
|
||||
size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1;
|
||||
|
||||
std::vector<uint8_t> colors;
|
||||
colors.resize(numVerts*numVerts*4);
|
||||
std::vector<float> positions;
|
||||
positions.resize(numVerts*numVerts*3);
|
||||
std::vector<float> normals;
|
||||
normals.resize(numVerts*numVerts*3);
|
||||
|
||||
Ogre::Vector3 normal;
|
||||
Ogre::ColourValue color;
|
||||
|
||||
float vertY;
|
||||
float vertX;
|
||||
|
||||
float vertY_ = 0; // of current cell corner
|
||||
for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY)
|
||||
{
|
||||
float vertX_ = 0; // of current cell corner
|
||||
for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX)
|
||||
{
|
||||
ESM::Land* land = getLand(cellX, cellY);
|
||||
if (land && !land->mHasData)
|
||||
land = NULL;
|
||||
bool hasColors = land && land->mLandData->mUsingColours;
|
||||
|
||||
int rowStart = 0;
|
||||
int colStart = 0;
|
||||
// Skip the first row / column unless we're at a chunk edge,
|
||||
// since this row / column is already contained in a previous cell
|
||||
if (colStart == 0 && vertY_ != 0)
|
||||
colStart += increment;
|
||||
if (rowStart == 0 && vertX_ != 0)
|
||||
rowStart += increment;
|
||||
|
||||
vertY = vertY_;
|
||||
for (int col=colStart; col<ESM::Land::LAND_SIZE; col += increment)
|
||||
{
|
||||
vertX = vertX_;
|
||||
for (int row=rowStart; row<ESM::Land::LAND_SIZE; row += increment)
|
||||
{
|
||||
positions[vertX*numVerts*3 + vertY*3] = ((vertX/float(numVerts-1)-0.5) * size * 8192);
|
||||
positions[vertX*numVerts*3 + vertY*3 + 1] = ((vertY/float(numVerts-1)-0.5) * size * 8192);
|
||||
if (land)
|
||||
positions[vertX*numVerts*3 + vertY*3 + 2] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row];
|
||||
else
|
||||
positions[vertX*numVerts*3 + vertY*3 + 2] = -2048;
|
||||
|
||||
if (land)
|
||||
{
|
||||
normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
|
||||
normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
|
||||
normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
|
||||
normal.normalise();
|
||||
}
|
||||
else
|
||||
normal = Ogre::Vector3(0,0,1);
|
||||
|
||||
// Normals apparently don't connect seamlessly between cells
|
||||
if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1)
|
||||
fixNormal(normal, cellX, cellY, col, row);
|
||||
|
||||
// some corner normals appear to be complete garbage (z < 0)
|
||||
if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1))
|
||||
averageNormal(normal, cellX, cellY, col, row);
|
||||
|
||||
assert(normal.z > 0);
|
||||
|
||||
normals[vertX*numVerts*3 + vertY*3] = normal.x;
|
||||
normals[vertX*numVerts*3 + vertY*3 + 1] = normal.y;
|
||||
normals[vertX*numVerts*3 + vertY*3 + 2] = normal.z;
|
||||
|
||||
if (hasColors)
|
||||
{
|
||||
color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f;
|
||||
color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f;
|
||||
color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
color.r = 1;
|
||||
color.g = 1;
|
||||
color.b = 1;
|
||||
}
|
||||
|
||||
// Unlike normals, colors mostly connect seamlessly between cells, but not always...
|
||||
if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1)
|
||||
fixColour(color, cellX, cellY, col, row);
|
||||
|
||||
color.a = 1;
|
||||
Ogre::uint32 rsColor;
|
||||
Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor);
|
||||
memcpy(&colors[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32));
|
||||
|
||||
++vertX;
|
||||
}
|
||||
++vertY;
|
||||
}
|
||||
vertX_ = vertX;
|
||||
}
|
||||
vertY_ = vertY;
|
||||
|
||||
assert(vertX_ == numVerts); // Ensure we covered whole area
|
||||
}
|
||||
assert(vertY_ == numVerts); // Ensure we covered whole area
|
||||
|
||||
vertexBuffer->writeData(0, vertexBuffer->getSizeInBytes(), &positions[0], true);
|
||||
normalBuffer->writeData(0, normalBuffer->getSizeInBytes(), &normals[0], true);
|
||||
colourBuffer->writeData(0, colourBuffer->getSizeInBytes(), &colors[0], true);
|
||||
}
|
||||
|
||||
TerrainStorage::UniqueTextureId TerrainStorage::getVtexIndexAt(int cellX, int cellY,
|
||||
int x, int y)
|
||||
{
|
||||
// For the first/last row/column, we need to get the texture from the neighbour cell
|
||||
// to get consistent blending at the borders
|
||||
--x;
|
||||
if (x < 0)
|
||||
{
|
||||
--cellX;
|
||||
x += ESM::Land::LAND_TEXTURE_SIZE;
|
||||
}
|
||||
if (y >= ESM::Land::LAND_TEXTURE_SIZE) // Y appears to be wrapped from the other side because why the hell not?
|
||||
{
|
||||
++cellY;
|
||||
y -= ESM::Land::LAND_TEXTURE_SIZE;
|
||||
}
|
||||
|
||||
assert(x<ESM::Land::LAND_TEXTURE_SIZE);
|
||||
assert(y<ESM::Land::LAND_TEXTURE_SIZE);
|
||||
|
||||
ESM::Land* land = getLand(cellX, cellY);
|
||||
if (land)
|
||||
{
|
||||
if (!land->isDataLoaded(ESM::Land::DATA_VTEX))
|
||||
land->loadData(ESM::Land::DATA_VTEX);
|
||||
|
||||
int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
|
||||
if (tex == 0)
|
||||
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin
|
||||
return std::make_pair(tex, land->mPlugin);
|
||||
}
|
||||
else
|
||||
return std::make_pair(0,0);
|
||||
}
|
||||
|
||||
std::string TerrainStorage::getTextureName(UniqueTextureId id)
|
||||
{
|
||||
if (id.first == 0)
|
||||
return "_land_default.dds"; // Not sure if the default texture floatly is hardcoded?
|
||||
|
||||
// NB: All vtex ids are +1 compared to the ltex ids
|
||||
const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second);
|
||||
|
||||
std::string texture = ltex->mTexture;
|
||||
//TODO this is needed due to MWs messed up texture handling
|
||||
texture = texture.substr(0, texture.rfind(".")) + ".dds";
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void TerrainStorage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter,
|
||||
bool pack, std::vector<Ogre::TexturePtr> &blendmaps, std::vector<Terrain::LayerInfo> &layerList)
|
||||
{
|
||||
// TODO - blending isn't completely right yet; the blending radius appears to be
|
||||
// different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap
|
||||
// and interpolate the rest of the cell by hand? :/
|
||||
|
||||
Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f);
|
||||
int cellX = origin.x;
|
||||
int cellY = origin.y;
|
||||
|
||||
// Save the used texture indices so we know the total number of textures
|
||||
// and number of required blend maps
|
||||
std::set<UniqueTextureId> textureIndices;
|
||||
// Due to the way the blending works, the base layer will always shine through in between
|
||||
// blend transitions (eg halfway between two texels, both blend values will be 0.5, so 25% of base layer visible).
|
||||
// To get a consistent look, we need to make sure to use the same base layer in all cells.
|
||||
// So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell.
|
||||
textureIndices.insert(std::make_pair(0,0));
|
||||
|
||||
for (int y=0; y<ESM::Land::LAND_TEXTURE_SIZE+1; ++y)
|
||||
for (int x=0; x<ESM::Land::LAND_TEXTURE_SIZE+1; ++x)
|
||||
{
|
||||
UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y);
|
||||
textureIndices.insert(id);
|
||||
}
|
||||
|
||||
// Makes sure the indices are sorted, or rather,
|
||||
// retrieved as sorted. This is important to keep the splatting order
|
||||
// consistent across cells.
|
||||
std::map<UniqueTextureId, int> textureIndicesMap;
|
||||
for (std::set<UniqueTextureId>::iterator it = textureIndices.begin(); it != textureIndices.end(); ++it)
|
||||
{
|
||||
int size = textureIndicesMap.size();
|
||||
textureIndicesMap[*it] = size;
|
||||
layerList.push_back(getLayerInfo(getTextureName(*it)));
|
||||
}
|
||||
|
||||
int numTextures = textureIndices.size();
|
||||
// numTextures-1 since the base layer doesn't need blending
|
||||
int numBlendmaps = pack ? std::ceil((numTextures-1) / 4.f) : (numTextures-1);
|
||||
|
||||
int channels = pack ? 4 : 1;
|
||||
|
||||
// Second iteration - create and fill in the blend maps
|
||||
const int blendmapSize = ESM::Land::LAND_TEXTURE_SIZE+1;
|
||||
std::vector<Ogre::uchar> data;
|
||||
data.resize(blendmapSize * blendmapSize * channels, 0);
|
||||
|
||||
for (int i=0; i<numBlendmaps; ++i)
|
||||
{
|
||||
Ogre::PixelFormat format = pack ? Ogre::PF_A8B8G8R8 : Ogre::PF_A8;
|
||||
static int count=0;
|
||||
Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/"
|
||||
+ Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D, blendmapSize, blendmapSize, 0, format);
|
||||
|
||||
for (int y=0; y<blendmapSize; ++y)
|
||||
{
|
||||
for (int x=0; x<blendmapSize; ++x)
|
||||
{
|
||||
UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y);
|
||||
int layerIndex = textureIndicesMap.find(id)->second;
|
||||
int blendIndex = (pack ? std::floor((layerIndex-1)/4.f) : layerIndex-1);
|
||||
int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0;
|
||||
|
||||
if (blendIndex == i)
|
||||
data[y*blendmapSize*channels + x*channels + channel] = 255;
|
||||
else
|
||||
data[y*blendmapSize*channels + x*channels + channel] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// All done, upload to GPU
|
||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
|
||||
map->loadRawData(stream, blendmapSize, blendmapSize, format);
|
||||
blendmaps.push_back(map);
|
||||
}
|
||||
}
|
||||
|
||||
float TerrainStorage::getHeightAt(const Ogre::Vector3 &worldPos)
|
||||
{
|
||||
int cellX = std::floor(worldPos.x / 8192.f);
|
||||
int cellY = std::floor(worldPos.y / 8192.f);
|
||||
|
||||
ESM::Land* land = getLand(cellX, cellY);
|
||||
if (!land)
|
||||
return -2048;
|
||||
|
||||
// Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition
|
||||
|
||||
// Normalized position in the cell
|
||||
float nX = (worldPos.x - (cellX * 8192))/8192.f;
|
||||
float nY = (worldPos.y - (cellY * 8192))/8192.f;
|
||||
|
||||
// get left / bottom points (rounded down)
|
||||
float factor = ESM::Land::LAND_SIZE - 1.0f;
|
||||
float invFactor = 1.0f / factor;
|
||||
|
||||
int startX = static_cast<int>(nX * factor);
|
||||
int startY = static_cast<int>(nY * factor);
|
||||
int endX = startX + 1;
|
||||
int endY = startY + 1;
|
||||
|
||||
assert(endX < ESM::Land::LAND_SIZE);
|
||||
assert(endY < ESM::Land::LAND_SIZE);
|
||||
|
||||
// now get points in terrain space (effectively rounding them to boundaries)
|
||||
float startXTS = startX * invFactor;
|
||||
float startYTS = startY * invFactor;
|
||||
float endXTS = endX * invFactor;
|
||||
float endYTS = endY * invFactor;
|
||||
|
||||
// get parametric from start coord to next point
|
||||
float xParam = (nX - startXTS) * factor;
|
||||
float yParam = (nY - startYTS) * factor;
|
||||
|
||||
/* For even / odd tri strip rows, triangles are this shape:
|
||||
even odd
|
||||
3---2 3---2
|
||||
| / | | \ |
|
||||
0---1 0---1
|
||||
*/
|
||||
|
||||
// Build all 4 positions in normalized cell space, using point-sampled height
|
||||
Ogre::Vector3 v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f);
|
||||
Ogre::Vector3 v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f);
|
||||
Ogre::Vector3 v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f);
|
||||
Ogre::Vector3 v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f);
|
||||
// define this plane in terrain space
|
||||
Ogre::Plane plane;
|
||||
// (At the moment, all rows have the same triangle alignment)
|
||||
if (true)
|
||||
{
|
||||
// odd row
|
||||
bool secondTri = ((1.0 - yParam) > xParam);
|
||||
if (secondTri)
|
||||
plane.redefine(v0, v1, v3);
|
||||
else
|
||||
plane.redefine(v1, v2, v3);
|
||||
}
|
||||
else
|
||||
{
|
||||
// even row
|
||||
bool secondTri = (yParam > xParam);
|
||||
if (secondTri)
|
||||
plane.redefine(v0, v2, v3);
|
||||
else
|
||||
plane.redefine(v0, v1, v2);
|
||||
}
|
||||
|
||||
// Solve plane equation for z
|
||||
return (-plane.normal.x * nX
|
||||
-plane.normal.y * nY
|
||||
- plane.d) / plane.normal.z * 8192;
|
||||
|
||||
}
|
||||
|
||||
float TerrainStorage::getVertexHeight(const ESM::Land *land, int x, int y)
|
||||
{
|
||||
assert(x < ESM::Land::LAND_SIZE);
|
||||
assert(y < ESM::Land::LAND_SIZE);
|
||||
return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x];
|
||||
}
|
||||
|
||||
Terrain::LayerInfo TerrainStorage::getLayerInfo(const std::string& texture)
|
||||
{
|
||||
// Already have this cached?
|
||||
if (mLayerInfoMap.find(texture) != mLayerInfoMap.end())
|
||||
return mLayerInfoMap[texture];
|
||||
|
||||
Terrain::LayerInfo info;
|
||||
info.mParallax = false;
|
||||
info.mSpecular = false;
|
||||
info.mDiffuseMap = "textures\\" + texture;
|
||||
std::string texture_ = texture;
|
||||
boost::replace_last(texture_, ".", "_nh.");
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_))
|
||||
{
|
||||
info.mNormalMap = "textures\\" + texture_;
|
||||
info.mParallax = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
texture_ = texture;
|
||||
boost::replace_last(texture_, ".", "_n.");
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_))
|
||||
info.mNormalMap = "textures\\" + texture_;
|
||||
}
|
||||
|
||||
texture_ = texture;
|
||||
boost::replace_last(texture_, ".", "_diffusespec.");
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_))
|
||||
{
|
||||
info.mDiffuseMap = "textures\\" + texture_;
|
||||
info.mSpecular = true;
|
||||
}
|
||||
|
||||
mLayerInfoMap[texture] = info;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Terrain::LayerInfo TerrainStorage::getDefaultLayer()
|
||||
{
|
||||
Terrain::LayerInfo info;
|
||||
info.mDiffuseMap = "textures\\_land_default.dds";
|
||||
info.mParallax = false;
|
||||
info.mSpecular = false;
|
||||
return info;
|
||||
}
|
||||
|
||||
float TerrainStorage::getCellWorldSize()
|
||||
{
|
||||
return ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
int TerrainStorage::getCellVertices()
|
||||
{
|
||||
return ESM::Land::LAND_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,8 +12,75 @@ namespace MWRender
|
|||
virtual ESM::Land* getLand (int cellX, int cellY);
|
||||
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
||||
public:
|
||||
|
||||
/// Get bounds of the whole terrain in cell units
|
||||
virtual Ogre::AxisAlignedBox getBounds();
|
||||
///< Get bounds in cell units
|
||||
|
||||
/// Get the minimum and maximum heights of a terrain chunk.
|
||||
/// @note Should only be called for chunks <= 1 cell, i.e. leafs of the quad tree.
|
||||
/// Larger chunks can simply merge AABB of children.
|
||||
/// @param size size of the chunk in cell units
|
||||
/// @param center center of the chunk in cell units
|
||||
/// @param min min height will be stored here
|
||||
/// @param max max height will be stored here
|
||||
/// @return true if there was data available for this terrain chunk
|
||||
virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max);
|
||||
|
||||
/// Fill vertex buffers for a terrain chunk.
|
||||
/// @param lodLevel LOD level, 0 = most detailed
|
||||
/// @param size size of the terrain chunk in cell units
|
||||
/// @param center center of the chunk in cell units
|
||||
/// @param vertexBuffer buffer to write vertices
|
||||
/// @param normalBuffer buffer to write vertex normals
|
||||
/// @param colourBuffer buffer to write vertex colours
|
||||
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
|
||||
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
|
||||
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
|
||||
Ogre::HardwareVertexBufferSharedPtr colourBuffer);
|
||||
|
||||
/// Create textures holding layer blend values for a terrain chunk.
|
||||
/// @note The terrain chunk shouldn't be larger than one cell since otherwise we might
|
||||
/// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used.
|
||||
/// @param chunkSize size of the terrain chunk in cell units
|
||||
/// @param chunkCenter center of the chunk in cell units
|
||||
/// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) -
|
||||
/// otherwise, each texture contains blend values for one layer only. Shader-based rendering
|
||||
/// can utilize packing, FFP can't.
|
||||
/// @param blendmaps created blendmaps will be written here
|
||||
/// @param layerList names of the layer textures used will be written here
|
||||
virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack,
|
||||
std::vector<Ogre::TexturePtr>& blendmaps,
|
||||
std::vector<Terrain::LayerInfo>& layerList);
|
||||
|
||||
virtual float getHeightAt (const Ogre::Vector3& worldPos);
|
||||
|
||||
virtual Terrain::LayerInfo getDefaultLayer();
|
||||
|
||||
/// Get the transformation factor for mapping cell units to world units.
|
||||
virtual float getCellWorldSize();
|
||||
|
||||
/// Get the number of vertices on one side for each cell. Should be (power of two)+1
|
||||
virtual int getCellVertices();
|
||||
|
||||
private:
|
||||
void fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row);
|
||||
void fixColour (Ogre::ColourValue& colour, int cellX, int cellY, int col, int row);
|
||||
void averageNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row);
|
||||
|
||||
float getVertexHeight (const ESM::Land* land, int x, int y);
|
||||
|
||||
// Since plugins can define new texture palettes, we need to know the plugin index too
|
||||
// in order to retrieve the correct texture name.
|
||||
// pair <texture id, plugin id>
|
||||
typedef std::pair<short, short> UniqueTextureId;
|
||||
|
||||
UniqueTextureId getVtexIndexAt(int cellX, int cellY,
|
||||
int x, int y);
|
||||
std::string getTextureName (UniqueTextureId id);
|
||||
|
||||
std::map<std::string, Terrain::LayerInfo> mLayerInfoMap;
|
||||
|
||||
Terrain::LayerInfo getLayerInfo(const std::string& texture);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -28,16 +30,32 @@ namespace MWScript
|
|||
return MWBase::Environment::get().getWorld()->getGlobalVariableType (name);
|
||||
}
|
||||
|
||||
char CompilerContext::getMemberType (const std::string& name, const std::string& id) const
|
||||
std::pair<char, bool> CompilerContext::getMemberType (const std::string& name,
|
||||
const std::string& id) const
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
|
||||
std::string script;
|
||||
bool reference = false;
|
||||
|
||||
std::string script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
if (const ESM::Script *scriptRecord =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().search (id))
|
||||
{
|
||||
script = scriptRecord->mId;
|
||||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
|
||||
|
||||
if (script.empty())
|
||||
return ' ';
|
||||
script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
reference = true;
|
||||
}
|
||||
|
||||
return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name);
|
||||
char type = ' ';
|
||||
|
||||
if (!script.empty())
|
||||
type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (
|
||||
Misc::StringUtils::lowerCase (name));
|
||||
|
||||
return std::make_pair (type, reference);
|
||||
}
|
||||
|
||||
bool CompilerContext::isId (const std::string& name) const
|
||||
|
@ -67,4 +85,14 @@ namespace MWScript
|
|||
store.get<ESM::Static>().search (name) ||
|
||||
store.get<ESM::Weapon>().search (name);
|
||||
}
|
||||
|
||||
bool CompilerContext::isJournalId (const std::string& name) const
|
||||
{
|
||||
const MWWorld::ESMStore &store =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
const ESM::Dialogue *topic = store.get<ESM::Dialogue>().search (name);
|
||||
|
||||
return topic && topic->mType==ESM::Dialogue::Journal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,18 @@ namespace MWScript
|
|||
/// 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual char getGlobalType (const std::string& name) const;
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual std::pair<char, bool> getMemberType (const std::string& name,
|
||||
const std::string& id) const;
|
||||
///< Return type of member variable \a name in script \a id or in script of reference of
|
||||
/// \a id
|
||||
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
/// second: true: script of reference
|
||||
|
||||
virtual bool isId (const std::string& name) const;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
virtual bool isJournalId (const std::string& name) const;
|
||||
///< Does \a name match a journal ID?
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,9 @@ op 0x20023: AiFollow, explicit reference
|
|||
op 0x20024: AiFollowCell
|
||||
op 0x20025: AiFollowCell, explicit reference
|
||||
op 0x20026: ModRegion
|
||||
opcodes 0x20027-0x3ffff unused
|
||||
op 0x20027: RemoveSoulGem
|
||||
op 0x20028: RemoveSoulGem, explicit reference
|
||||
opcodes 0x20029-0x3ffff unused
|
||||
|
||||
Segment 4:
|
||||
(not implemented yet)
|
||||
|
@ -308,8 +310,8 @@ op 0x20001f1: GetDetected
|
|||
op 0x20001f2: GetDetected, explicit reference
|
||||
op 0x20001f3: AddSoulGem
|
||||
op 0x20001f4: AddSoulGem, explicit reference
|
||||
op 0x20001f5: RemoveSoulGem
|
||||
op 0x20001f6: RemoveSoulGem, explicit reference
|
||||
op 0x20001f5: unused
|
||||
op 0x20001f6: unused
|
||||
op 0x20001f7: PlayBink
|
||||
op 0x20001f8: Drop
|
||||
op 0x20001f9: Drop, explicit reference
|
||||
|
@ -381,5 +383,7 @@ op 0x200023a: StartCombat
|
|||
op 0x200023b: StartCombatExplicit
|
||||
op 0x200023c: StopCombat
|
||||
op 0x200023d: StopCombatExplicit
|
||||
op 0x200023e: GetPcInJail
|
||||
op 0x200023f: GetPcTraveling
|
||||
|
||||
opcodes 0x200023e-0x3ffffff unused
|
||||
opcodes 0x2000240-0x3ffffff unused
|
||||
|
|
|
@ -148,4 +148,25 @@ namespace MWScript
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
Locals& GlobalScripts::getLocals (const std::string& name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (name2);
|
||||
|
||||
if (iter==mScripts.end())
|
||||
{
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
|
||||
{
|
||||
Locals locals;
|
||||
|
||||
locals.configure (*script);
|
||||
|
||||
iter = mScripts.insert (std::make_pair (name, std::make_pair (false, locals))).first;
|
||||
}
|
||||
}
|
||||
|
||||
return iter->second.second;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ namespace MWScript
|
|||
///< Records for variables that do not exist are dropped silently.
|
||||
///
|
||||
/// \return Known type?
|
||||
|
||||
Locals& getLocals (const std::string& name);
|
||||
///< If the script \a name has not been added as a global script yet, it is added
|
||||
/// automatically, but is not set to running state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,47 @@ namespace MWScript
|
|||
}
|
||||
}
|
||||
|
||||
const Locals& InterpreterContext::getMemberLocals (std::string& id, bool global)
|
||||
const
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
return MWBase::Environment::get().getScriptManager()->getGlobalScripts().
|
||||
getLocals (id);
|
||||
}
|
||||
else
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
|
||||
id = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
|
||||
|
||||
return ptr.getRefData().getLocals();
|
||||
}
|
||||
}
|
||||
|
||||
Locals& InterpreterContext::getMemberLocals (std::string& id, bool global)
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
return MWBase::Environment::get().getScriptManager()->getGlobalScripts().
|
||||
getLocals (id);
|
||||
}
|
||||
else
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
|
||||
id = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
|
||||
|
||||
return ptr.getRefData().getLocals();
|
||||
}
|
||||
}
|
||||
|
||||
InterpreterContext::InterpreterContext (
|
||||
MWScript::Locals *locals, MWWorld::Ptr reference)
|
||||
: mLocals (locals), mReference (reference),
|
||||
|
@ -407,82 +448,80 @@ namespace MWScript
|
|||
MWBase::Environment::get().getWorld()->disable (ref);
|
||||
}
|
||||
|
||||
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const
|
||||
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
const Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
|
||||
scriptId, name, 's');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
return ptr.getRefData().getLocals().mShorts[index];
|
||||
return locals.mShorts[index];
|
||||
}
|
||||
|
||||
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const
|
||||
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
const Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
|
||||
scriptId, name, 'l');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
return ptr.getRefData().getLocals().mLongs[index];
|
||||
return locals.mLongs[index];
|
||||
}
|
||||
|
||||
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const
|
||||
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
const Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
|
||||
scriptId, name, 'f');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
return ptr.getRefData().getLocals().mFloats[index];
|
||||
return locals.mFloats[index];
|
||||
}
|
||||
|
||||
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value)
|
||||
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name,
|
||||
int value, bool global)
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
|
||||
int index =
|
||||
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
ptr.getRefData().getLocals().mShorts[index] = value;
|
||||
locals.mShorts[index] = value;
|
||||
}
|
||||
|
||||
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value)
|
||||
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value, bool global)
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
|
||||
int index =
|
||||
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
ptr.getRefData().getLocals().mLongs[index] = value;
|
||||
locals.mLongs[index] = value;
|
||||
}
|
||||
|
||||
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value)
|
||||
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
|
||||
int index =
|
||||
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
ptr.getRefData().getLocals().mFloats[index] = value;
|
||||
locals.mFloats[index] = value;
|
||||
}
|
||||
|
||||
MWWorld::Ptr InterpreterContext::getReference(bool required)
|
||||
|
|
|
@ -37,6 +37,12 @@ namespace MWScript
|
|||
|
||||
const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const;
|
||||
|
||||
const Locals& getMemberLocals (std::string& id, bool global) const;
|
||||
///< \a id is changed to the respective script ID, if \a id wasn't a script ID before
|
||||
|
||||
Locals& getMemberLocals (std::string& id, bool global);
|
||||
///< \a id is changed to the respective script ID, if \a id wasn't a script ID before
|
||||
|
||||
public:
|
||||
|
||||
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference);
|
||||
|
@ -75,35 +81,35 @@ namespace MWScript
|
|||
virtual void setGlobalLong (const std::string& name, int value);
|
||||
|
||||
virtual void setGlobalFloat (const std::string& name, float value);
|
||||
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const;
|
||||
|
||||
virtual char getGlobalType (const std::string& name) const;
|
||||
|
||||
|
||||
virtual std::string getActionBinding(const std::string& action) const;
|
||||
|
||||
|
||||
virtual std::string getNPCName() const;
|
||||
|
||||
|
||||
virtual std::string getNPCRace() const;
|
||||
|
||||
|
||||
virtual std::string getNPCClass() const;
|
||||
|
||||
|
||||
virtual std::string getNPCFaction() const;
|
||||
|
||||
virtual std::string getNPCRank() const;
|
||||
|
||||
|
||||
virtual std::string getPCName() const;
|
||||
|
||||
|
||||
virtual std::string getPCRace() const;
|
||||
|
||||
|
||||
virtual std::string getPCClass() const;
|
||||
|
||||
|
||||
virtual std::string getPCRank() const;
|
||||
|
||||
|
||||
virtual std::string getPCNextRank() const;
|
||||
|
||||
|
||||
virtual int getPCBounty() const;
|
||||
|
||||
|
||||
virtual std::string getCurrentCellName() const;
|
||||
|
||||
virtual bool isScriptRunning (const std::string& name) const;
|
||||
|
@ -138,17 +144,17 @@ namespace MWScript
|
|||
|
||||
virtual void disable (const std::string& id = "");
|
||||
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name) const;
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name) const;
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual float getMemberFloat (const std::string& id, const std::string& name) const;
|
||||
virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual void setMemberShort (const std::string& id, const std::string& name, int value);
|
||||
virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global);
|
||||
|
||||
virtual void setMemberLong (const std::string& id, const std::string& name, int value);
|
||||
virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global);
|
||||
|
||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value);
|
||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global);
|
||||
|
||||
MWWorld::Ptr getReference(bool required=true);
|
||||
///< Reference, that the script is running from (can be empty)
|
||||
|
|
|
@ -365,17 +365,21 @@ namespace MWScript
|
|||
};
|
||||
|
||||
template<class R>
|
||||
class OpRemoveSoulGem : public Interpreter::Opcode0
|
||||
class OpRemoveSoulGem : public Interpreter::Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
// throw away additional arguments
|
||||
for (unsigned int i=0; i<arg0; ++i)
|
||||
runtime.pop();
|
||||
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||
{
|
||||
|
@ -818,6 +822,28 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
class OpGetPcInJail : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime &runtime)
|
||||
{
|
||||
/// \todo implement jail check
|
||||
runtime.push (0);
|
||||
}
|
||||
};
|
||||
|
||||
class OpGetPcTraveling : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime &runtime)
|
||||
{
|
||||
/// \todo implement traveling check
|
||||
runtime.push (0);
|
||||
}
|
||||
};
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
|
||||
|
@ -850,8 +876,8 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Misc::opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
|
||||
interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
|
||||
interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>);
|
||||
|
@ -888,6 +914,8 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,22 +7,28 @@
|
|||
#include <exception>
|
||||
|
||||
#include <components/esm/loadscpt.hpp>
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/compiler/scanner.hpp>
|
||||
#include <components/compiler/context.hpp>
|
||||
#include <components/compiler/exception.hpp>
|
||||
#include <components/compiler/quickfileparser.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "extensions.hpp"
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose,
|
||||
Compiler::Context& compilerContext)
|
||||
Compiler::Context& compilerContext, int warningsMode)
|
||||
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
|
||||
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
|
||||
mOpcodesInstalled (false), mGlobalScripts (store)
|
||||
{}
|
||||
{
|
||||
mErrorHandler.setWarningsMode (warningsMode);
|
||||
}
|
||||
|
||||
bool ScriptManager::compile (const std::string& name)
|
||||
{
|
||||
|
@ -138,37 +144,33 @@ namespace MWScript
|
|||
|
||||
Compiler::Locals& ScriptManager::getLocals (const std::string& name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
{
|
||||
ScriptCollection::iterator iter = mScripts.find (name);
|
||||
ScriptCollection::iterator iter = mScripts.find (name2);
|
||||
|
||||
if (iter!=mScripts.end())
|
||||
return iter->second.second;
|
||||
}
|
||||
|
||||
{
|
||||
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name);
|
||||
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name2);
|
||||
|
||||
if (iter!=mOtherLocals.end())
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
Compiler::Locals locals;
|
||||
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2))
|
||||
{
|
||||
int index = 0;
|
||||
Compiler::Locals locals;
|
||||
|
||||
for (int i=0; i<script->mData.mNumShorts; ++i)
|
||||
locals.declare ('s', script->mVarNames[index++]);
|
||||
|
||||
for (int i=0; i<script->mData.mNumLongs; ++i)
|
||||
locals.declare ('l', script->mVarNames[index++]);
|
||||
|
||||
for (int i=0; i<script->mData.mNumFloats; ++i)
|
||||
locals.declare ('f', script->mVarNames[index++]);
|
||||
std::istringstream stream (script->mScriptText);
|
||||
Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals);
|
||||
Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions());
|
||||
scanner.scan (parser);
|
||||
|
||||
std::map<std::string, Compiler::Locals>::iterator iter =
|
||||
mOtherLocals.insert (std::make_pair (name, locals)).first;
|
||||
mOtherLocals.insert (std::make_pair (name2, locals)).first;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
@ -214,8 +216,10 @@ namespace MWScript
|
|||
throw std::runtime_error ("invalid variable type");
|
||||
}
|
||||
|
||||
std::string variable2 = Misc::StringUtils::lowerCase (variable);
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
if (script->mVarNames.at (i+offset)==variable)
|
||||
if (Misc::StringUtils::lowerCase (script->mVarNames.at (i+offset))==variable2)
|
||||
return i;
|
||||
|
||||
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace MWScript
|
|||
public:
|
||||
|
||||
ScriptManager (const MWWorld::ESMStore& store, bool verbose,
|
||||
Compiler::Context& compilerContext);
|
||||
Compiler::Context& compilerContext, int warningsMode);
|
||||
|
||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
|
||||
///< Run the script with the given name (compile first, if not compiled yet)
|
||||
|
|
|
@ -316,15 +316,25 @@ void OpenAL_SoundStream::play()
|
|||
throwALerror();
|
||||
mSamplesQueued = 0;
|
||||
|
||||
for(ALuint i = 0;i < sNumBuffers;i++)
|
||||
alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate);
|
||||
throwALerror();
|
||||
std::vector<char> data(mBufferSize);
|
||||
|
||||
alSourceQueueBuffers(mSource, sNumBuffers, mBuffers);
|
||||
bool finished = false;
|
||||
for(ALuint i = 0;i < sNumBuffers && !finished;i++)
|
||||
{
|
||||
size_t got = mDecoder->read(&data[0], data.size());
|
||||
finished = (got < data.size());
|
||||
if(got > 0)
|
||||
{
|
||||
ALuint bufid = mBuffers[i];
|
||||
alBufferData(bufid, mFormat, &data[0], got, mSampleRate);
|
||||
alSourceQueueBuffers(mSource, 1, &bufid);
|
||||
throwALerror();
|
||||
mSamplesQueued += getBufferSampleCount(bufid);
|
||||
}
|
||||
}
|
||||
|
||||
mIsFinished = finished;
|
||||
alSourcePlay(mSource);
|
||||
throwALerror();
|
||||
|
||||
mIsFinished = false;
|
||||
mOutput.mStreamThread->add(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||
+MWBase::Environment::get().getJournal()->countSavedGameRecords()
|
||||
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
|
||||
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
||||
+ 1 // global map
|
||||
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
|
||||
+1 // global map
|
||||
);
|
||||
|
||||
writer.save (stream);
|
||||
|
@ -203,6 +204,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||
writer.endRecord (ESM::REC_SAVE);
|
||||
|
||||
MWBase::Environment::get().getJournal()->write (writer);
|
||||
MWBase::Environment::get().getDialogueManager()->write (writer);
|
||||
MWBase::Environment::get().getWorld()->write (writer);
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
|
||||
MWBase::Environment::get().getWindowManager()->write(writer);
|
||||
|
@ -245,6 +247,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
|||
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
|
||||
break;
|
||||
|
||||
case ESM::REC_DIAS:
|
||||
|
||||
MWBase::Environment::get().getDialogueManager()->readRecord (reader, n.val);
|
||||
break;
|
||||
|
||||
case ESM::REC_ALCH:
|
||||
case ESM::REC_ARMO:
|
||||
case ESM::REC_BOOK:
|
||||
|
|
|
@ -529,12 +529,6 @@ namespace MWWorld
|
|||
return mPlayer->getPlayer();
|
||||
}
|
||||
|
||||
Ptr ptr = Class::get (mPlayer->getPlayer()).
|
||||
getContainerStore (mPlayer->getPlayer()).search (name);
|
||||
|
||||
if (!ptr.isEmpty())
|
||||
return ptr;
|
||||
|
||||
std::string lowerCaseName = Misc::StringUtils::lowerCase(name);
|
||||
|
||||
// active cells
|
||||
|
@ -548,6 +542,12 @@ namespace MWWorld
|
|||
return ptr;
|
||||
}
|
||||
|
||||
Ptr ptr = Class::get (mPlayer->getPlayer()).
|
||||
getContainerStore (mPlayer->getPlayer()).search (lowerCaseName);
|
||||
|
||||
if (!ptr.isEmpty())
|
||||
return ptr;
|
||||
|
||||
if (!activeOnly)
|
||||
{
|
||||
ret = mCells.getPtr (lowerCaseName);
|
||||
|
@ -610,6 +610,10 @@ namespace MWWorld
|
|||
|
||||
void World::enable (const Ptr& reference)
|
||||
{
|
||||
// enable is a no-op for items in containers
|
||||
if (!reference.isInCell())
|
||||
return;
|
||||
|
||||
if (!reference.getRefData().isEnabled())
|
||||
{
|
||||
reference.getRefData().enable();
|
||||
|
@ -640,6 +644,10 @@ namespace MWWorld
|
|||
|
||||
void World::disable (const Ptr& reference)
|
||||
{
|
||||
// disable is a no-op for items in containers
|
||||
if (!reference.isInCell())
|
||||
return;
|
||||
|
||||
if (reference.getRefData().isEnabled())
|
||||
{
|
||||
reference.getRefData().disable();
|
||||
|
|
|
@ -122,7 +122,6 @@ function(git_describe _var)
|
|||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(NOT res EQUAL 0)
|
||||
|
@ -147,7 +146,6 @@ function(get_git_tag_revision _var)
|
|||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
|
|
|
@ -44,7 +44,8 @@ add_component_dir (esm
|
|||
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
|
||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
||||
npcstats creaturestats
|
||||
)
|
||||
|
||||
add_component_dir (misc
|
||||
|
@ -59,7 +60,8 @@ add_component_dir (files
|
|||
add_component_dir (compiler
|
||||
context controlparser errorhandler exception exprparser extensions fileparser generator
|
||||
lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler
|
||||
stringparser tokenloc nullerrorhandler opcodes extensions0
|
||||
stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser
|
||||
quickfileparser
|
||||
)
|
||||
|
||||
add_component_dir (interpreter
|
||||
|
|
|
@ -33,11 +33,18 @@ namespace Compiler
|
|||
virtual char getGlobalType (const std::string& name) const = 0;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const = 0;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual std::pair<char, bool> getMemberType (const std::string& name,
|
||||
const std::string& id) const = 0;
|
||||
///< Return type of member variable \a name in script \a id or in script of reference of
|
||||
/// \a id
|
||||
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
/// second: true: script of reference
|
||||
|
||||
virtual bool isId (const std::string& name) const = 0;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
virtual bool isJournalId (const std::string& name) const = 0;
|
||||
///< Does \a name match a journal ID?
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "scanner.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "skipparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
|
@ -70,7 +72,7 @@ namespace Compiler
|
|||
}
|
||||
else if (keyword==Scanner::K_else)
|
||||
{
|
||||
mState = IfElseEndState;
|
||||
mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -106,7 +108,7 @@ namespace Compiler
|
|||
Codes expr;
|
||||
mExprParser.append (expr);
|
||||
|
||||
Generator::jump (loop, -static_cast<int> (mCodeBlock.size()-expr.size()));
|
||||
Generator::jump (loop, -static_cast<int> (mCodeBlock.size()+expr.size()));
|
||||
|
||||
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
|
||||
|
||||
|
@ -120,7 +122,7 @@ namespace Compiler
|
|||
|
||||
Codes loop2;
|
||||
|
||||
Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()-expr.size()-skip.size()));
|
||||
Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()+expr.size()+skip.size()));
|
||||
|
||||
if (loop.size()!=loop2.size())
|
||||
throw std::logic_error (
|
||||
|
@ -153,7 +155,7 @@ namespace Compiler
|
|||
}
|
||||
}
|
||||
|
||||
ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
ControlParser::ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
Literals& literals)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||
mLineParser (errorHandler, context, locals, literals, mCodeBlock),
|
||||
|
@ -186,8 +188,11 @@ namespace Compiler
|
|||
{
|
||||
if (mState==StartState)
|
||||
{
|
||||
if (keyword==Scanner::K_if)
|
||||
if (keyword==Scanner::K_if || keyword==Scanner::K_elseif)
|
||||
{
|
||||
if (keyword==Scanner::K_elseif)
|
||||
getErrorHandler().warning ("elseif without matching if", loc);
|
||||
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
|
@ -203,7 +208,8 @@ namespace Compiler
|
|||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
|
||||
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState ||
|
||||
mState==IfElseJunkState)
|
||||
{
|
||||
if (parseIfBody (keyword, loc, scanner))
|
||||
return true;
|
||||
|
@ -226,6 +232,7 @@ namespace Compiler
|
|||
case IfEndState: mState = IfBodyState; return true;
|
||||
case IfElseifEndState: mState = IfElseifBodyState; return true;
|
||||
case IfElseEndState: mState = IfElseBodyState; return true;
|
||||
case IfElseJunkState: mState = IfElseBodyState; return true;
|
||||
|
||||
case WhileEndState: mState = WhileBodyState; return true;
|
||||
|
||||
|
@ -243,7 +250,13 @@ namespace Compiler
|
|||
|
||||
default: ;
|
||||
}
|
||||
|
||||
}
|
||||
else if (code==Scanner::S_open && mState==IfElseJunkState)
|
||||
{
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
mState = IfElseBodyState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace Compiler
|
|||
IfElseEndState, IfElseBodyState,
|
||||
IfEndifState,
|
||||
WhileEndState, WhileBodyState,
|
||||
WhileEndwhileState
|
||||
WhileEndwhileState,
|
||||
IfElseJunkState
|
||||
};
|
||||
|
||||
typedef std::vector<Interpreter::Type_Code> Codes;
|
||||
|
@ -47,7 +48,7 @@ namespace Compiler
|
|||
|
||||
public:
|
||||
|
||||
ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
Literals& literals);
|
||||
|
||||
void appendCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||
|
|
83
components/compiler/declarationparser.cpp
Normal file
83
components/compiler/declarationparser.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
|
||||
#include "declarationparser.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "skipparser.hpp"
|
||||
#include "locals.hpp"
|
||||
|
||||
Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, const Context& context,
|
||||
Locals& locals)
|
||||
: Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0)
|
||||
{}
|
||||
|
||||
bool Compiler::DeclarationParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==State_Name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
/// \todo add option to make re-declared local variables an error
|
||||
getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)",
|
||||
loc);
|
||||
|
||||
mState = State_End;
|
||||
return true;
|
||||
}
|
||||
|
||||
mLocals.declare (mType, name2);
|
||||
|
||||
mState = State_End;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
bool Compiler::DeclarationParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==State_Begin)
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case Scanner::K_short: mType = 's'; break;
|
||||
case Scanner::K_long: mType = 'l'; break;
|
||||
case Scanner::K_float: mType = 'f'; break;
|
||||
default: mType = 0;
|
||||
}
|
||||
|
||||
if (mType)
|
||||
{
|
||||
mState = State_Name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==State_Name)
|
||||
{
|
||||
// allow keywords to be used as local variable names. MW script compiler, you suck!
|
||||
/// \todo option to disable this atrocity.
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline && mState==State_End)
|
||||
return false;
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void Compiler::DeclarationParser::reset()
|
||||
{
|
||||
mState = State_Begin;
|
||||
}
|
43
components/compiler/declarationparser.hpp
Normal file
43
components/compiler/declarationparser.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef COMPILER_DECLARATIONPARSER_H_INCLUDED
|
||||
#define COMPILER_DECLARATIONPARSER_H_INCLUDED
|
||||
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
|
||||
class DeclarationParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
State_Begin, State_Name, State_End
|
||||
};
|
||||
|
||||
Locals& mLocals;
|
||||
State mState;
|
||||
char mType;
|
||||
|
||||
public:
|
||||
|
||||
DeclarationParser (ErrorHandler& errorHandler, const Context& context, Locals& locals);
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a keyword token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
|
||||
void reset();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -5,7 +5,7 @@ namespace Compiler
|
|||
{
|
||||
// constructor
|
||||
|
||||
ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0) {}
|
||||
ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0), mWarningsMode (1) {}
|
||||
|
||||
// destructor
|
||||
|
||||
|
@ -36,8 +36,13 @@ namespace Compiler
|
|||
|
||||
void ErrorHandler::warning (const std::string& message, const TokenLoc& loc)
|
||||
{
|
||||
++mWarnings;
|
||||
report (message, loc, WarningMessage);
|
||||
if (mWarningsMode==1)
|
||||
{
|
||||
++mWarnings;
|
||||
report (message, loc, WarningMessage);
|
||||
}
|
||||
else if (mWarningsMode==2)
|
||||
error (message, loc);
|
||||
}
|
||||
|
||||
// Generate an error message.
|
||||
|
@ -62,4 +67,9 @@ namespace Compiler
|
|||
{
|
||||
mErrors = mWarnings = 0;
|
||||
}
|
||||
|
||||
void ErrorHandler::setWarningsMode (int mode)
|
||||
{
|
||||
mWarningsMode = mode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Compiler
|
|||
{
|
||||
int mWarnings;
|
||||
int mErrors;
|
||||
int mWarningsMode;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -60,8 +61,11 @@ namespace Compiler
|
|||
void endOfFile();
|
||||
///< Generate an error message for an unexpected EOF.
|
||||
|
||||
virtual void reset();
|
||||
virtual void reset();
|
||||
///< Remove all previous error/warning events
|
||||
|
||||
void setWarningsMode (int mode);
|
||||
///< // 0 ignore, 1 rate as warning, 2 rate as error
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <stack>
|
||||
#include <iterator>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "generator.hpp"
|
||||
#include "scanner.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
|
@ -14,7 +16,6 @@
|
|||
#include "stringparser.hpp"
|
||||
#include "extensions.hpp"
|
||||
#include "context.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
|
@ -203,21 +204,22 @@ namespace Compiler
|
|||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
std::string id = Misc::StringUtils::lowerCase (mExplicit);
|
||||
|
||||
char type = getContext().getMemberType (name2, id);
|
||||
std::pair<char, bool> type = getContext().getMemberType (name2, id);
|
||||
|
||||
if (type!=' ')
|
||||
if (type.first!=' ')
|
||||
{
|
||||
Generator::fetchMember (mCode, mLiterals, type, name2, id);
|
||||
Generator::fetchMember (mCode, mLiterals, type.first, name2, id, !type.second);
|
||||
|
||||
mNextOperand = false;
|
||||
mExplicit.clear();
|
||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||
mOperands.push_back (type.first=='f' ? 'f' : 'l');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
ExprParser::ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
Literals& literals, bool argument)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||
mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false)
|
||||
|
@ -308,6 +310,22 @@ namespace Compiler
|
|||
return true;
|
||||
}
|
||||
|
||||
// die in a fire, Morrowind script compiler!
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
if (getContext().isJournalId (name2))
|
||||
{
|
||||
// JournalID used as an argument. Use the index of that JournalID
|
||||
Generator::pushString (mCode, mLiterals, name2);
|
||||
int keyword = extensions->searchKeyword ("getjournalindex");
|
||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit, 0);
|
||||
mNextOperand = false;
|
||||
mOperands.push_back ('l');
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (mExplicit.empty() && getContext().isId (name2))
|
||||
{
|
||||
mExplicit = name2;
|
||||
|
@ -326,6 +344,31 @@ namespace Compiler
|
|||
|
||||
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
std::string argumentType; // ignored
|
||||
bool hasExplicit = false; // ignored
|
||||
if (extensions->isInstruction (keyword, argumentType, hasExplicit))
|
||||
{
|
||||
// pretend this is not a keyword
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
}
|
||||
|
||||
if (keyword==Scanner::K_end || keyword==Scanner::K_begin ||
|
||||
keyword==Scanner::K_short || keyword==Scanner::K_long ||
|
||||
keyword==Scanner::K_float || keyword==Scanner::K_if ||
|
||||
keyword==Scanner::K_endif || keyword==Scanner::K_else ||
|
||||
keyword==Scanner::K_elseif || keyword==Scanner::K_while ||
|
||||
keyword==Scanner::K_endwhile || keyword==Scanner::K_return ||
|
||||
keyword==Scanner::K_messagebox || keyword==Scanner::K_set ||
|
||||
keyword==Scanner::K_to || keyword==Scanner::K_startscript ||
|
||||
keyword==Scanner::K_stopscript || keyword==Scanner::K_enable ||
|
||||
keyword==Scanner::K_disable)
|
||||
{
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
|
||||
mFirst = false;
|
||||
|
||||
if (!mExplicit.empty())
|
||||
|
@ -368,8 +411,15 @@ namespace Compiler
|
|||
char returnType;
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, true))
|
||||
bool hasExplicit = true;
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
|
||||
{
|
||||
if (!hasExplicit)
|
||||
{
|
||||
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
|
||||
mExplicit.clear();
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
@ -490,7 +540,9 @@ namespace Compiler
|
|||
char returnType;
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, false))
|
||||
bool hasExplicit = false;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
|
||||
{
|
||||
mTokenLoc = loc;
|
||||
int optionals = parseArguments (argumentType, scanner);
|
||||
|
@ -518,6 +570,14 @@ namespace Compiler
|
|||
{
|
||||
if (!mExplicit.empty())
|
||||
{
|
||||
if (mRefOp && code==Scanner::S_open)
|
||||
{
|
||||
/// \todo add option to disable this workaround
|
||||
mOperators.push_back ('(');
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mRefOp && code==Scanner::S_ref)
|
||||
{
|
||||
mRefOp = true;
|
||||
|
@ -687,11 +747,11 @@ namespace Compiler
|
|||
{
|
||||
optional = true;
|
||||
}
|
||||
else if (*iter=='S' || *iter=='c')
|
||||
else if (*iter=='S' || *iter=='c' || *iter=='x')
|
||||
{
|
||||
stringParser.reset();
|
||||
|
||||
if (optional)
|
||||
if (optional || *iter=='x')
|
||||
stringParser.setOptional (true);
|
||||
|
||||
if (*iter=='c') stringParser.smashCase();
|
||||
|
@ -700,18 +760,21 @@ namespace Compiler
|
|||
if (optional && stringParser.isEmpty())
|
||||
break;
|
||||
|
||||
if (invert)
|
||||
if (*iter!='x')
|
||||
{
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
stringParser.append (tmp);
|
||||
if (invert)
|
||||
{
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
stringParser.append (tmp);
|
||||
|
||||
stack.push (tmp);
|
||||
stack.push (tmp);
|
||||
}
|
||||
else
|
||||
stringParser.append (code);
|
||||
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
}
|
||||
else
|
||||
stringParser.append (code);
|
||||
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace Compiler
|
|||
|
||||
public:
|
||||
|
||||
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
Literals& literals, bool argument = false);
|
||||
///< constructor
|
||||
/// \param argument Parser is used to parse function- or instruction-
|
||||
|
@ -101,6 +101,7 @@ namespace Compiler
|
|||
/// \param arguments Each character represents one arguments ('l': integer,
|
||||
/// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
|
||||
/// optional)
|
||||
/// 'x': optional string that will be ignored (die in a fire, MW script compiler!)
|
||||
/// \param invert Store arguments in reverted order.
|
||||
/// \return number of optional arguments
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Compiler
|
|||
}
|
||||
|
||||
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||
bool explicitReference) const
|
||||
bool& explicitReference) const
|
||||
{
|
||||
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
||||
|
||||
|
@ -30,7 +30,7 @@ namespace Compiler
|
|||
return false;
|
||||
|
||||
if (explicitReference && iter->second.mCodeExplicit==-1)
|
||||
return false;
|
||||
explicitReference = false;
|
||||
|
||||
returnType = iter->second.mReturn;
|
||||
argumentType = iter->second.mArguments;
|
||||
|
@ -38,7 +38,7 @@ namespace Compiler
|
|||
}
|
||||
|
||||
bool Extensions::isInstruction (int keyword, std::string& argumentType,
|
||||
bool explicitReference) const
|
||||
bool& explicitReference) const
|
||||
{
|
||||
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace Compiler
|
|||
return false;
|
||||
|
||||
if (explicitReference && iter->second.mCodeExplicit==-1)
|
||||
return false;
|
||||
explicitReference = false;
|
||||
|
||||
argumentType = iter->second.mArguments;
|
||||
return true;
|
||||
|
|
|
@ -47,13 +47,17 @@ namespace Compiler
|
|||
/// - keyword must be all lower case.
|
||||
|
||||
bool isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||
bool explicitReference) const;
|
||||
bool& explicitReference) const;
|
||||
///< Is this keyword registered with a function? If yes, return return and argument
|
||||
/// types.
|
||||
/// \param explicitReference In: has explicit reference; Out: set to false, if
|
||||
/// explicit reference is not available for this instruction.
|
||||
|
||||
bool isInstruction (int keyword, std::string& argumentType,
|
||||
bool explicitReference) const;
|
||||
bool& explicitReference) const;
|
||||
///< Is this keyword registered with a function? If yes, return argument types.
|
||||
/// \param explicitReference In: has explicit reference; Out: set to false, if
|
||||
/// explicit reference is not available for this instruction.
|
||||
|
||||
void registerFunction (const std::string& keyword, char returnType,
|
||||
const std::string& argumentType, int code, int codeExplicit = -1);
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Compiler
|
|||
opcodeAiEscortCellExplicit);
|
||||
extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander,
|
||||
opcodeAiWanderExplicit);
|
||||
extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow,
|
||||
extensions.registerInstruction ("aifollow", "cffff/llllllll", opcodeAiFollow,
|
||||
opcodeAiFollowExplicit);
|
||||
extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell,
|
||||
opcodeAiFollowCellExplicit);
|
||||
|
@ -62,7 +62,7 @@ namespace Compiler
|
|||
extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI);
|
||||
extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI);
|
||||
extensions.registerInstruction("startcombat", "c", opcodeStartCombat, opcodeStartCombatExplicit);
|
||||
extensions.registerInstruction("stopcombat", "", opcodeStopCombat, opcodeStopCombatExplicit);
|
||||
extensions.registerInstruction("stopcombat", "x", opcodeStopCombat, opcodeStopCombatExplicit);
|
||||
extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
|
||||
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
|
||||
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
|
||||
|
@ -190,7 +190,7 @@ namespace Compiler
|
|||
extensions.registerInstruction ("enableclassmenu", "", opcodeEnableClassMenu);
|
||||
extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu);
|
||||
extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu);
|
||||
extensions.registerInstruction ("enablestatreviewmenu", "",
|
||||
extensions.registerInstruction ("enablestatreviewmenu", "",
|
||||
opcodeEnableStatsReviewMenu);
|
||||
|
||||
extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu);
|
||||
|
@ -253,7 +253,7 @@ namespace Compiler
|
|||
extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit);
|
||||
extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit);
|
||||
extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit);
|
||||
extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit);
|
||||
extensions.registerInstruction ("removesoulgem", "c/l", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit);
|
||||
extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit);
|
||||
extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit);
|
||||
extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit);
|
||||
|
@ -276,6 +276,8 @@ namespace Compiler
|
|||
extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode);
|
||||
extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation);
|
||||
extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation);
|
||||
extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail);
|
||||
extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +398,7 @@ namespace Compiler
|
|||
extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
|
||||
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);
|
||||
|
||||
extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit);
|
||||
extensions.registerInstruction ("addspell", "cx", opcodeAddSpell, opcodeAddSpellExplicit);
|
||||
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
|
||||
opcodeRemoveSpellExplicit);
|
||||
extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects,
|
||||
|
|
|
@ -260,34 +260,34 @@ namespace
|
|||
code.push_back (Compiler::Generator::segment5 (44));
|
||||
}
|
||||
|
||||
void opStoreMemberShort (Compiler::Generator::CodeContainer& code)
|
||||
void opStoreMemberShort (Compiler::Generator::CodeContainer& code, bool global)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (59));
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 65 : 59));
|
||||
}
|
||||
|
||||
void opStoreMemberLong (Compiler::Generator::CodeContainer& code)
|
||||
void opStoreMemberLong (Compiler::Generator::CodeContainer& code, bool global)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (60));
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 66 : 60));
|
||||
}
|
||||
|
||||
void opStoreMemberFloat (Compiler::Generator::CodeContainer& code)
|
||||
void opStoreMemberFloat (Compiler::Generator::CodeContainer& code, bool global)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (61));
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 67 : 61));
|
||||
}
|
||||
|
||||
void opFetchMemberShort (Compiler::Generator::CodeContainer& code)
|
||||
void opFetchMemberShort (Compiler::Generator::CodeContainer& code, bool global)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (62));
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 68 : 62));
|
||||
}
|
||||
|
||||
void opFetchMemberLong (Compiler::Generator::CodeContainer& code)
|
||||
void opFetchMemberLong (Compiler::Generator::CodeContainer& code, bool global)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (63));
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 69 : 63));
|
||||
}
|
||||
|
||||
void opFetchMemberFloat (Compiler::Generator::CodeContainer& code)
|
||||
void opFetchMemberFloat (Compiler::Generator::CodeContainer& code, bool global)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (64));
|
||||
code.push_back (Compiler::Generator::segment5 (global ? 70 : 64));
|
||||
}
|
||||
|
||||
void opRandom (Compiler::Generator::CodeContainer& code)
|
||||
|
@ -593,7 +593,7 @@ namespace Compiler
|
|||
else if (offset<0)
|
||||
opJumpBackward (code, -offset);
|
||||
else
|
||||
throw std::logic_error ("inifite loop");
|
||||
throw std::logic_error ("infinite loop");
|
||||
}
|
||||
|
||||
void jumpOnZero (CodeContainer& code, int offset)
|
||||
|
@ -738,7 +738,8 @@ namespace Compiler
|
|||
}
|
||||
|
||||
void assignToMember (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const std::string& id, const CodeContainer& value, char valueType)
|
||||
const std::string& name, const std::string& id, const CodeContainer& value,
|
||||
char valueType, bool global)
|
||||
{
|
||||
int index = literals.addString (name);
|
||||
|
||||
|
@ -766,17 +767,17 @@ namespace Compiler
|
|||
{
|
||||
case 'f':
|
||||
|
||||
opStoreMemberFloat (code);
|
||||
opStoreMemberFloat (code, global);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opStoreMemberShort (code);
|
||||
opStoreMemberShort (code, global);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opStoreMemberLong (code);
|
||||
opStoreMemberLong (code, global);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -786,7 +787,7 @@ namespace Compiler
|
|||
}
|
||||
|
||||
void fetchMember (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const std::string& id)
|
||||
const std::string& name, const std::string& id, bool global)
|
||||
{
|
||||
int index = literals.addString (name);
|
||||
|
||||
|
@ -800,17 +801,17 @@ namespace Compiler
|
|||
{
|
||||
case 'f':
|
||||
|
||||
opFetchMemberFloat (code);
|
||||
opFetchMemberFloat (code, global);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opFetchMemberShort (code);
|
||||
opFetchMemberShort (code, global);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opFetchMemberLong (code);
|
||||
opFetchMemberLong (code, global);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -102,10 +102,12 @@ namespace Compiler
|
|||
const std::string& name);
|
||||
|
||||
void assignToMember (CodeContainer& code, Literals& literals, char memberType,
|
||||
const std::string& name, const std::string& id, const CodeContainer& value, char valueType);
|
||||
const std::string& name, const std::string& id, const CodeContainer& value, char valueType, bool global);
|
||||
///< \param global Member of a global script instead of a script of a reference.
|
||||
|
||||
void fetchMember (CodeContainer& code, Literals& literals, char memberType,
|
||||
const std::string& name, const std::string& id);
|
||||
const std::string& name, const std::string& id, bool global);
|
||||
///< \param global Member of a global script instead of a script of a reference.
|
||||
|
||||
void random (CodeContainer& code);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#include "lineparser.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "context.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
|
@ -8,7 +10,7 @@
|
|||
#include "locals.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "extensions.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include "declarationparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
|
@ -48,7 +50,7 @@ namespace Compiler
|
|||
}
|
||||
}
|
||||
|
||||
LineParser::LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
LineParser::LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
Literals& literals, std::vector<Interpreter::Type_Code>& code, bool allowExpression)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code),
|
||||
mState (BeginState), mExprParser (errorHandler, context, locals, literals),
|
||||
|
@ -82,33 +84,9 @@ namespace Compiler
|
|||
bool LineParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==ShortState || mState==LongState || mState==FloatState)
|
||||
if (mState==PotentialEndState)
|
||||
{
|
||||
if (!getContext().canDeclareLocals())
|
||||
{
|
||||
getErrorHandler().error ("local variables can't be declared in this context", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
/// \todo add option to make re-declared local variables an error
|
||||
getErrorHandler().warning ("can't re-declare local variable", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'),
|
||||
name2);
|
||||
|
||||
getErrorHandler().warning ("stay string argument (ignoring it)", loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
@ -142,12 +120,13 @@ namespace Compiler
|
|||
if (mState==SetMemberVarState)
|
||||
{
|
||||
mMemberName = name;
|
||||
char type = getContext().getMemberType (mMemberName, mName);
|
||||
std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
|
||||
|
||||
if (type!=' ')
|
||||
if (type.first!=' ')
|
||||
{
|
||||
mState = SetMemberVarState2;
|
||||
mType = type;
|
||||
mType = type.first;
|
||||
mReferenceMember = type.second;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -240,6 +219,34 @@ namespace Compiler
|
|||
|
||||
bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==SetMemberVarState)
|
||||
{
|
||||
mMemberName = loc.mLiteral;
|
||||
std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
|
||||
|
||||
if (type.first!=' ')
|
||||
{
|
||||
mState = SetMemberVarState2;
|
||||
mType = type.first;
|
||||
mReferenceMember = type.second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mState==SetPotentialMemberVarState && keyword==Scanner::K_to)
|
||||
{
|
||||
getErrorHandler().warning ("unknown variable (ignoring set instruction)", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mState==SetState)
|
||||
{
|
||||
// allow keywords to be used as variable names when assigning a value to a variable.
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
|
||||
if (mState==BeginState || mState==ExplicitState)
|
||||
{
|
||||
switch (keyword)
|
||||
|
@ -247,13 +254,13 @@ namespace Compiler
|
|||
case Scanner::K_enable:
|
||||
|
||||
Generator::enable (mCode, mLiterals, mExplicit);
|
||||
mState = EndState;
|
||||
mState = PotentialEndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_disable:
|
||||
|
||||
Generator::disable (mCode, mLiterals, mExplicit);
|
||||
mState = EndState;
|
||||
mState = PotentialEndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -262,8 +269,15 @@ namespace Compiler
|
|||
{
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState))
|
||||
bool hasExplicit = mState==ExplicitState;
|
||||
if (extensions->isInstruction (keyword, argumentType, hasExplicit))
|
||||
{
|
||||
if (!hasExplicit && mState==ExplicitState)
|
||||
{
|
||||
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
|
||||
mExplicit.clear();
|
||||
}
|
||||
|
||||
int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
|
||||
|
||||
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
|
||||
|
@ -287,9 +301,16 @@ namespace Compiler
|
|||
char returnType;
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType,
|
||||
!mExplicit.empty()))
|
||||
bool hasExplicit = !mExplicit.empty();
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
|
||||
{
|
||||
if (!hasExplicit && !mExplicit.empty())
|
||||
{
|
||||
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
|
||||
mExplicit.clear();
|
||||
}
|
||||
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
parseExpression (scanner, loc);
|
||||
mState = EndState;
|
||||
|
@ -299,13 +320,38 @@ namespace Compiler
|
|||
}
|
||||
}
|
||||
|
||||
if (mState==ExplicitState)
|
||||
{
|
||||
// drop stray explicit reference
|
||||
getErrorHandler().warning ("stray explicit reference (ignoring it)", loc);
|
||||
mState = BeginState;
|
||||
mExplicit.clear();
|
||||
}
|
||||
|
||||
if (mState==BeginState)
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case Scanner::K_short: mState = ShortState; return true;
|
||||
case Scanner::K_long: mState = LongState; return true;
|
||||
case Scanner::K_float: mState = FloatState; return true;
|
||||
case Scanner::K_short:
|
||||
case Scanner::K_long:
|
||||
case Scanner::K_float:
|
||||
{
|
||||
if (!getContext().canDeclareLocals())
|
||||
{
|
||||
getErrorHandler().error (
|
||||
"local variables can't be declared in this context", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return true;
|
||||
}
|
||||
|
||||
DeclarationParser declaration (getErrorHandler(), getContext(), mLocals);
|
||||
if (declaration.parseKeyword (keyword, loc, scanner))
|
||||
scanner.scan (declaration);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case Scanner::K_set: mState = SetState; return true;
|
||||
case Scanner::K_messagebox: mState = MessageState; return true;
|
||||
|
||||
|
@ -328,6 +374,24 @@ namespace Compiler
|
|||
Generator::stopScript (mCode);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_else:
|
||||
|
||||
getErrorHandler().warning ("stay else (ignoring it)", loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_endif:
|
||||
|
||||
getErrorHandler().warning ("stay endif (ignoring it)", loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_begin:
|
||||
|
||||
getErrorHandler().warning ("stay begin (ignoring it)", loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==SetLocalVarState && keyword==Scanner::K_to)
|
||||
|
@ -365,7 +429,8 @@ namespace Compiler
|
|||
std::vector<Interpreter::Type_Code> code;
|
||||
char type = mExprParser.append (code);
|
||||
|
||||
Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type);
|
||||
Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type,
|
||||
!mReferenceMember);
|
||||
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
@ -389,7 +454,8 @@ namespace Compiler
|
|||
|
||||
bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline && (mState==EndState || mState==BeginState))
|
||||
if (code==Scanner::S_newline &&
|
||||
(mState==EndState || mState==BeginState || mState==PotentialEndState))
|
||||
return false;
|
||||
|
||||
if (code==Scanner::S_comma && mState==MessageState)
|
||||
|
|
|
@ -20,11 +20,10 @@ namespace Compiler
|
|||
enum State
|
||||
{
|
||||
BeginState,
|
||||
ShortState, LongState, FloatState,
|
||||
SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState,
|
||||
SetMemberVarState, SetMemberVarState2,
|
||||
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
|
||||
EndState,
|
||||
EndState, PotentialEndState /* may have a stray string argument */,
|
||||
PotentialExplicitState, ExplicitState, MemberState
|
||||
};
|
||||
|
||||
|
@ -34,6 +33,7 @@ namespace Compiler
|
|||
State mState;
|
||||
std::string mName;
|
||||
std::string mMemberName;
|
||||
bool mReferenceMember;
|
||||
int mButtons;
|
||||
std::string mExplicit;
|
||||
char mType;
|
||||
|
@ -44,7 +44,7 @@ namespace Compiler
|
|||
|
||||
public:
|
||||
|
||||
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
Literals& literals, std::vector<Interpreter::Type_Code>& code,
|
||||
bool allowExpression = false);
|
||||
///< \param allowExpression Allow lines consisting of a naked expression
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <ostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
const std::vector<std::string>& Locals::get (char type) const
|
||||
|
@ -97,7 +99,7 @@ namespace Compiler
|
|||
|
||||
void Locals::declare (char type, const std::string& name)
|
||||
{
|
||||
get (type).push_back (name);
|
||||
get (type).push_back (Misc::StringUtils::lowerCase (name));
|
||||
}
|
||||
|
||||
void Locals::clear()
|
||||
|
|
|
@ -203,8 +203,8 @@ namespace Compiler
|
|||
const int opcodeGetEffectExplicit = 0x20001d0;
|
||||
const int opcodeAddSoulGem = 0x20001f3;
|
||||
const int opcodeAddSoulGemExplicit = 0x20001f4;
|
||||
const int opcodeRemoveSoulGem = 0x20001f5;
|
||||
const int opcodeRemoveSoulGemExplicit = 0x20001f6;
|
||||
const int opcodeRemoveSoulGem = 0x20027;
|
||||
const int opcodeRemoveSoulGemExplicit = 0x20028;
|
||||
const int opcodeDrop = 0x20001f8;
|
||||
const int opcodeDropExplicit = 0x20001f9;
|
||||
const int opcodeDropSoulGem = 0x20001fa;
|
||||
|
@ -245,6 +245,8 @@ namespace Compiler
|
|||
const int opcodeCastExplicit = 0x2000228;
|
||||
const int opcodeExplodeSpell = 0x2000229;
|
||||
const int opcodeExplodeSpellExplicit = 0x200022a;
|
||||
const int opcodeGetPcInJail = 0x200023e;
|
||||
const int opcodeGetPcTraveling = 0x200023f;
|
||||
}
|
||||
|
||||
namespace Sky
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Compiler
|
|||
|
||||
// Return context
|
||||
|
||||
Context& Parser::getContext()
|
||||
const Context& Parser::getContext() const
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ namespace Compiler
|
|||
return lowerCase;
|
||||
}
|
||||
|
||||
Parser::Parser (ErrorHandler& errorHandler, Context& context)
|
||||
Parser::Parser (ErrorHandler& errorHandler, const Context& context)
|
||||
: mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
|
||||
{}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Compiler
|
|||
class Parser
|
||||
{
|
||||
ErrorHandler& mErrorHandler;
|
||||
Context& mContext;
|
||||
const Context& mContext;
|
||||
bool mOptional;
|
||||
bool mEmpty;
|
||||
|
||||
|
@ -38,14 +38,14 @@ namespace Compiler
|
|||
ErrorHandler& getErrorHandler();
|
||||
///< Return error handler
|
||||
|
||||
Context& getContext();
|
||||
const Context& getContext() const;
|
||||
///< Return context
|
||||
|
||||
static std::string toLower (const std::string& name);
|
||||
|
||||
public:
|
||||
|
||||
Parser (ErrorHandler& errorHandler, Context& context);
|
||||
Parser (ErrorHandler& errorHandler, const Context& context);
|
||||
///< constructor
|
||||
|
||||
virtual ~Parser();
|
||||
|
|
52
components/compiler/quickfileparser.cpp
Normal file
52
components/compiler/quickfileparser.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
|
||||
#include "quickfileparser.hpp"
|
||||
|
||||
#include "skipparser.hpp"
|
||||
#include "scanner.hpp"
|
||||
|
||||
Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, const Context& context,
|
||||
Locals& locals)
|
||||
: Parser (errorHandler, context), mDeclarationParser (errorHandler, context, locals)
|
||||
{}
|
||||
|
||||
bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (keyword==Scanner::K_end)
|
||||
return false;
|
||||
|
||||
if (keyword==Scanner::K_short || keyword==Scanner::K_long || keyword==Scanner::K_float)
|
||||
{
|
||||
mDeclarationParser.reset();
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
scanner.scan (mDeclarationParser);
|
||||
return true;
|
||||
}
|
||||
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code!=Scanner::S_newline)
|
||||
{
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Compiler::QuickFileParser::parseEOF (Scanner& scanner)
|
||||
{
|
||||
|
||||
}
|
39
components/compiler/quickfileparser.hpp
Normal file
39
components/compiler/quickfileparser.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef COMPILER_QUICKFILEPARSER_H_INCLUDED
|
||||
#define COMPILER_QUICKFILEPARSER_H_INCLUDED
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "declarationparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
|
||||
/// \brief File parser variant that ignores everything but variable declarations
|
||||
class QuickFileParser : public Parser
|
||||
{
|
||||
DeclarationParser mDeclarationParser;
|
||||
|
||||
public:
|
||||
|
||||
QuickFileParser (ErrorHandler& errorHandler, const Context& context, Locals& locals);
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a keyword token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -370,9 +370,9 @@ namespace Compiler
|
|||
|
||||
if (c=='\n')
|
||||
special = S_newline;
|
||||
else if (c=='(')
|
||||
else if (c=='(' || c=='[') /// \todo option to disable the use of [ as alias for (
|
||||
special = S_open;
|
||||
else if (c==')')
|
||||
else if (c==')' || c==']') /// \todo option to disable the use of ] as alias for )
|
||||
special = S_close;
|
||||
else if (c=='.')
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Compiler
|
||||
{
|
||||
ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context,
|
||||
ScriptParser::ScriptParser (ErrorHandler& errorHandler, const Context& context,
|
||||
Locals& locals, bool end)
|
||||
: Parser (errorHandler, context), mOutput (locals),
|
||||
mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()),
|
||||
|
@ -32,7 +32,7 @@ namespace Compiler
|
|||
|
||||
bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (keyword==Scanner::K_while || keyword==Scanner::K_if)
|
||||
if (keyword==Scanner::K_while || keyword==Scanner::K_if || keyword==Scanner::K_elseif)
|
||||
{
|
||||
mControlParser.reset();
|
||||
if (mControlParser.parseKeyword (keyword, loc, scanner))
|
||||
|
@ -71,6 +71,12 @@ namespace Compiler
|
|||
if (code==Scanner::S_newline) // empty line
|
||||
return true;
|
||||
|
||||
if (code==Scanner::S_open) /// \todo Option to switch this off
|
||||
{
|
||||
scanner.putbackSpecial (code, loc);
|
||||
return parseKeyword (Scanner::K_if, loc, scanner);
|
||||
}
|
||||
|
||||
mLineParser.reset();
|
||||
if (mLineParser.parseSpecial (code, loc, scanner))
|
||||
scanner.scan (mLineParser);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Compiler
|
|||
class Locals;
|
||||
|
||||
// Script parser, to be used in dialogue scripts and as part of FileParser
|
||||
|
||||
|
||||
class ScriptParser : public Parser
|
||||
{
|
||||
Output mOutput;
|
||||
|
@ -21,14 +21,14 @@ namespace Compiler
|
|||
bool mEnd;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/// \param end of script is marked by end keyword.
|
||||
ScriptParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
ScriptParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
|
||||
bool end = false);
|
||||
|
||||
|
||||
void getCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||
///< store generated code in \æ code.
|
||||
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
|
@ -43,8 +43,8 @@ namespace Compiler
|
|||
/// \return fetch another token?
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
|
||||
///< Handle EOF token.
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state.
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace Compiler
|
||||
{
|
||||
SkipParser::SkipParser (ErrorHandler& errorHandler, Context& context)
|
||||
SkipParser::SkipParser (ErrorHandler& errorHandler, const Context& context)
|
||||
: Parser (errorHandler, context)
|
||||
{}
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace Compiler
|
|||
{
|
||||
if (code==Scanner::S_newline)
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ namespace Compiler
|
|||
// \brief Skip parser for skipping a line
|
||||
//
|
||||
// This parser is mainly intended for skipping the rest of a faulty line.
|
||||
|
||||
|
||||
class SkipParser : public Parser
|
||||
{
|
||||
public:
|
||||
|
||||
SkipParser (ErrorHandler& errorHandler, Context& context);
|
||||
|
||||
|
||||
SkipParser (ErrorHandler& errorHandler, const Context& context);
|
||||
|
||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle an int token.
|
||||
/// \return fetch another token?
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Compiler
|
||||
{
|
||||
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
|
||||
StringParser::StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals)
|
||||
: Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
|
||||
{
|
||||
|
||||
|
|
|
@ -10,22 +10,22 @@
|
|||
namespace Compiler
|
||||
{
|
||||
class Literals;
|
||||
|
||||
|
||||
class StringParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
StartState, CommaState
|
||||
};
|
||||
|
||||
|
||||
Literals& mLiterals;
|
||||
State mState;
|
||||
std::vector<Interpreter::Type_Code> mCode;
|
||||
bool mSmashCase;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals);
|
||||
|
||||
StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals);
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
|
@ -35,15 +35,15 @@ namespace Compiler
|
|||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
|
||||
|
||||
void append (std::vector<Interpreter::Type_Code>& code);
|
||||
///< Append code for parsed string.
|
||||
|
||||
|
||||
void smashCase();
|
||||
///< Transform all scanned strings to lower case
|
||||
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state (this includes the smashCase function).
|
||||
///< Reset parser to clean state (this includes the smashCase function).
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ void ESM::CreatureState::load (ESMReader &esm)
|
|||
ObjectState::load (esm);
|
||||
|
||||
mInventory.load (esm);
|
||||
|
||||
mCreatureStats.load (esm);
|
||||
}
|
||||
|
||||
void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const
|
||||
|
@ -13,4 +15,6 @@ void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const
|
|||
ObjectState::save (esm, inInventory);
|
||||
|
||||
mInventory.save (esm);
|
||||
|
||||
mCreatureStats.save (esm);
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "objectstate.hpp"
|
||||
#include "inventorystate.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -11,6 +12,7 @@ namespace ESM
|
|||
struct CreatureState : public ObjectState
|
||||
{
|
||||
InventoryState mInventory;
|
||||
CreatureStats mCreatureStats;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
|
|
20
components/esm/creaturestats.cpp
Normal file
20
components/esm/creaturestats.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
void ESM::CreatureStats::load (ESMReader &esm)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
mAttributes[i].load (esm);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].load (esm);
|
||||
}
|
||||
|
||||
void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
mAttributes[i].save (esm);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].save (esm);
|
||||
}
|
27
components/esm/creaturestats.hpp
Normal file
27
components/esm/creaturestats.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef OPENMW_ESM_CREATURESTATS_H
|
||||
#define OPENMW_ESM_CREATURESTATS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "statstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// format 0, saved games only
|
||||
|
||||
struct CreatureStats
|
||||
{
|
||||
StatState<int> mAttributes[8];
|
||||
StatState<float> mDynamic[3];
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -91,6 +91,7 @@ enum RecNameInts
|
|||
REC_PLAY = 0x59414c50,
|
||||
REC_CSTA = 0x41545343,
|
||||
REC_GMAP = 0x50414d47,
|
||||
REC_DIAS = 0x53414944,
|
||||
|
||||
// format 1
|
||||
REC_FILT = 0x544C4946
|
||||
|
|
21
components/esm/dialoguestate.cpp
Normal file
21
components/esm/dialoguestate.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
#include "dialoguestate.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
void ESM::DialogueState::load (ESMReader &esm)
|
||||
{
|
||||
while (esm.isNextSub ("TOPI"))
|
||||
mKnownTopics.push_back (esm.getHString());
|
||||
}
|
||||
|
||||
void ESM::DialogueState::save (ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator iter (mKnownTopics.begin());
|
||||
iter!=mKnownTopics.end(); ++iter)
|
||||
{
|
||||
esm.writeHNString ("TOPI", *iter);
|
||||
|
||||
}
|
||||
}
|
23
components/esm/dialoguestate.hpp
Normal file
23
components/esm/dialoguestate.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef OPENMW_ESM_DIALOGUESTATE_H
|
||||
#define OPENMW_ESM_DIALOGUESTATE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// format 0, saved games only
|
||||
|
||||
struct DialogueState
|
||||
{
|
||||
std::vector<std::string> mKnownTopics;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -6,6 +6,10 @@ void ESM::NpcState::load (ESMReader &esm)
|
|||
ObjectState::load (esm);
|
||||
|
||||
mInventory.load (esm);
|
||||
|
||||
mNpcStats.load (esm);
|
||||
|
||||
mCreatureStats.load (esm);
|
||||
}
|
||||
|
||||
void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const
|
||||
|
@ -13,4 +17,8 @@ void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const
|
|||
ObjectState::save (esm, inInventory);
|
||||
|
||||
mInventory.save (esm);
|
||||
|
||||
mNpcStats.save (esm);
|
||||
|
||||
mCreatureStats.save (esm);
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "objectstate.hpp"
|
||||
#include "inventorystate.hpp"
|
||||
#include "npcstats.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -11,6 +13,8 @@ namespace ESM
|
|||
struct NpcState : public ObjectState
|
||||
{
|
||||
InventoryState mInventory;
|
||||
NpcStats mNpcStats;
|
||||
CreatureStats mCreatureStats;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
|
|
133
components/esm/npcstats.cpp
Normal file
133
components/esm/npcstats.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
|
||||
#include "npcstats.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
ESM::NpcStats::Faction::Faction() : mExpelled (false), mRank (0), mReputation (0) {}
|
||||
|
||||
void ESM::NpcStats::load (ESMReader &esm)
|
||||
{
|
||||
while (esm.isNextSub ("FACT"))
|
||||
{
|
||||
std::string id = esm.getHString();
|
||||
|
||||
Faction faction;
|
||||
|
||||
int expelled = 0;
|
||||
esm.getHNOT (expelled, "FAEX");
|
||||
|
||||
if (expelled)
|
||||
faction.mExpelled = true;
|
||||
|
||||
esm.getHNOT (faction.mRank, "FARA");
|
||||
|
||||
esm.getHNOT (faction.mReputation, "FARE");
|
||||
|
||||
mFactions.insert (std::make_pair (id, faction));
|
||||
}
|
||||
|
||||
mDisposition = 0;
|
||||
esm.getHNOT (mDisposition, "DISP");
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
{
|
||||
mSkills[i].mRegular.load (esm);
|
||||
mSkills[i].mWerewolf.load (esm);
|
||||
}
|
||||
|
||||
mBounty = 0;
|
||||
esm.getHNOT (mBounty, "BOUN");
|
||||
|
||||
mReputation = 0;
|
||||
esm.getHNOT (mReputation, "REPU");
|
||||
|
||||
mWerewolfKills = 0;
|
||||
esm.getHNOT (mWerewolfKills, "WKIL");
|
||||
|
||||
mProfit = 0;
|
||||
esm.getHNOT (mProfit, "PROF");
|
||||
|
||||
mAttackStrength = 0;
|
||||
esm.getHNOT (mAttackStrength, "ASTR");
|
||||
|
||||
mLevelProgress = 0;
|
||||
esm.getHNOT (mLevelProgress, "LPRO");
|
||||
|
||||
esm.getHNT (mSkillIncrease, "INCR");
|
||||
|
||||
while (esm.isNextSub ("USED"))
|
||||
mUsedIds.push_back (esm.getHString());
|
||||
|
||||
mTimeToStartDrowning = 0;
|
||||
esm.getHNOT (mTimeToStartDrowning, "DRTI");
|
||||
|
||||
mLastDrowningHit = 0;
|
||||
esm.getHNOT (mLastDrowningHit, "DRLH");
|
||||
|
||||
mLevelHealthBonus = 0;
|
||||
esm.getHNOT (mLevelHealthBonus, "LVLH");
|
||||
}
|
||||
|
||||
void ESM::NpcStats::save (ESMWriter &esm) const
|
||||
{
|
||||
for (std::map<std::string, Faction>::const_iterator iter (mFactions.begin());
|
||||
iter!=mFactions.end(); ++iter)
|
||||
{
|
||||
esm.writeHNString ("FACT", iter->first);
|
||||
|
||||
if (iter->second.mExpelled)
|
||||
{
|
||||
int expelled = 1;
|
||||
esm.writeHNT ("FAEX", expelled);
|
||||
}
|
||||
|
||||
if (iter->second.mRank)
|
||||
esm.writeHNT ("FARA", iter->second.mRank);
|
||||
|
||||
if (iter->second.mReputation)
|
||||
esm.writeHNT ("FARE", iter->second.mReputation);
|
||||
}
|
||||
|
||||
if (mDisposition)
|
||||
esm.writeHNT ("DISP", mDisposition);
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
{
|
||||
mSkills[i].mRegular.save (esm);
|
||||
mSkills[i].mWerewolf.save (esm);
|
||||
}
|
||||
|
||||
if (mBounty)
|
||||
esm.writeHNT ("BOUN", mBounty);
|
||||
|
||||
if (mReputation)
|
||||
esm.writeHNT ("REPU", mReputation);
|
||||
|
||||
if (mWerewolfKills)
|
||||
esm.writeHNT ("WKIL", mWerewolfKills);
|
||||
|
||||
if (mProfit)
|
||||
esm.writeHNT ("PROF", mProfit);
|
||||
|
||||
if (mAttackStrength)
|
||||
esm.writeHNT ("ASTR", mAttackStrength);
|
||||
|
||||
if (mLevelProgress)
|
||||
esm.writeHNT ("LPRO", mLevelProgress);
|
||||
|
||||
esm.writeHNT ("INCR", mSkillIncrease);
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (mUsedIds.begin()); iter!=mUsedIds.end();
|
||||
++iter)
|
||||
esm.writeHNT ("USED", *iter);
|
||||
|
||||
if (mTimeToStartDrowning)
|
||||
esm.writeHNT ("DRTI", mTimeToStartDrowning);
|
||||
|
||||
if (mLastDrowningHit)
|
||||
esm.writeHNT ("DRLH", mLastDrowningHit);
|
||||
|
||||
if (mLevelHealthBonus)
|
||||
esm.writeHNT ("LVLH", mLevelHealthBonus);
|
||||
}
|
54
components/esm/npcstats.hpp
Normal file
54
components/esm/npcstats.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef OPENMW_ESM_NPCSTATS_H
|
||||
#define OPENMW_ESM_NPCSTATS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "statstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// format 0, saved games only
|
||||
|
||||
struct NpcStats
|
||||
{
|
||||
struct Skill
|
||||
{
|
||||
StatState<int> mRegular;
|
||||
StatState<int> mWerewolf;
|
||||
};
|
||||
|
||||
struct Faction
|
||||
{
|
||||
bool mExpelled;
|
||||
int mRank;
|
||||
int mReputation;
|
||||
|
||||
Faction();
|
||||
};
|
||||
|
||||
std::map<std::string, Faction> mFactions;
|
||||
int mDisposition;
|
||||
Skill mSkills[27];
|
||||
int mBounty;
|
||||
int mReputation;
|
||||
int mWerewolfKills;
|
||||
int mProfit;
|
||||
float mAttackStrength;
|
||||
int mLevelProgress;
|
||||
int mSkillIncrease[8];
|
||||
std::vector<std::string> mUsedIds;
|
||||
float mTimeToStartDrowning;
|
||||
float mLastDrowningHit;
|
||||
float mLevelHealthBonus;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
59
components/esm/statstate.hpp
Normal file
59
components/esm/statstate.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef OPENMW_ESM_STATSTATE_H
|
||||
#define OPENMW_ESM_STATSTATE_H
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
// format 0, saved games only
|
||||
|
||||
template<typename T>
|
||||
struct StatState
|
||||
{
|
||||
T mBase;
|
||||
T mMod;
|
||||
T mCurrent;
|
||||
T mDamage;
|
||||
float mProgress;
|
||||
|
||||
StatState();
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
StatState<T>::StatState() : mBase (0), mMod (0), mCurrent (0), mDamage (0), mProgress (0) {}
|
||||
|
||||
template<typename T>
|
||||
void StatState<T>::load (ESMReader &esm)
|
||||
{
|
||||
esm.getHNT (mBase, "STBA");
|
||||
esm.getHNT (mMod, "STMO");
|
||||
mCurrent = 0;
|
||||
esm.getHNOT (mCurrent, "STCU");
|
||||
mDamage = 0;
|
||||
esm.getHNOT (mDamage, "STDA");
|
||||
mProgress = 0;
|
||||
esm.getHNOT (mProgress, "STPR");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void StatState<T>::save (ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT ("STBA", mBase);
|
||||
esm.writeHNT ("STMO", mMod);
|
||||
|
||||
if (mCurrent)
|
||||
esm.writeHNT ("STCU", mCurrent);
|
||||
|
||||
if (mDamage)
|
||||
esm.writeHNT ("STDA", mDamage);
|
||||
|
||||
if (mProgress)
|
||||
esm.writeHNT ("STPR", mProgress);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -50,33 +50,33 @@ namespace Interpreter
|
|||
virtual void setGlobalFloat (const std::string& name, float value) = 0;
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const = 0;
|
||||
|
||||
|
||||
virtual char getGlobalType (const std::string& name) const = 0;
|
||||
|
||||
virtual std::string getActionBinding(const std::string& action) const = 0;
|
||||
|
||||
|
||||
virtual std::string getNPCName() const = 0;
|
||||
|
||||
|
||||
virtual std::string getNPCRace() const = 0;
|
||||
|
||||
|
||||
virtual std::string getNPCClass() const = 0;
|
||||
|
||||
|
||||
virtual std::string getNPCFaction() const = 0;
|
||||
|
||||
|
||||
virtual std::string getNPCRank() const = 0;
|
||||
|
||||
virtual std::string getPCName() const = 0;
|
||||
|
||||
|
||||
virtual std::string getPCRace() const = 0;
|
||||
|
||||
|
||||
virtual std::string getPCClass() const = 0;
|
||||
|
||||
|
||||
virtual std::string getPCRank() const = 0;
|
||||
|
||||
|
||||
virtual std::string getPCNextRank() const = 0;
|
||||
|
||||
|
||||
virtual int getPCBounty() const = 0;
|
||||
|
||||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
|
||||
virtual bool isScriptRunning (const std::string& name) const = 0;
|
||||
|
@ -96,17 +96,17 @@ namespace Interpreter
|
|||
|
||||
virtual void disable (const std::string& id = "") = 0;
|
||||
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name) const = 0;
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0;
|
||||
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name) const = 0;
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0;
|
||||
|
||||
virtual float getMemberFloat (const std::string& id, const std::string& name) const = 0;
|
||||
virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const = 0;
|
||||
|
||||
virtual void setMemberShort (const std::string& id, const std::string& name, int value) = 0;
|
||||
virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global) = 0;
|
||||
|
||||
virtual void setMemberLong (const std::string& id, const std::string& name, int value) = 0;
|
||||
virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global) = 0;
|
||||
|
||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value)
|
||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
|
||||
= 0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -127,5 +127,11 @@ op 61: store stack[0] in member float stack[2] of object with ID stack[1]
|
|||
op 62: replace stack[0] with member short stack[1] of object with ID stack[0]
|
||||
op 63: replace stack[0] with member short stack[1] of object with ID stack[0]
|
||||
op 64: replace stack[0] with member short stack[1] of object with ID stack[0]
|
||||
opcodes 65-33554431 unused
|
||||
op 65: store stack[0] in member short stack[2] of global script with ID stack[1]
|
||||
op 66: store stack[0] in member long stack[2] of global script with ID stack[1]
|
||||
op 67: store stack[0] in member float stack[2] of global script with ID stack[1]
|
||||
op 68: replace stack[0] with member short stack[1] of global script with ID stack[0]
|
||||
op 69: replace stack[0] with member short stack[1] of global script with ID stack[0]
|
||||
op 70: replace stack[0] with member short stack[1] of global script with ID stack[0]
|
||||
opcodes 71-33554431 unused
|
||||
opcodes 33554432-67108863 reserved for extensions
|
||||
|
|
|
@ -40,12 +40,18 @@ namespace Interpreter
|
|||
interpreter.installSegment5 (42, new OpFetchGlobalShort);
|
||||
interpreter.installSegment5 (43, new OpFetchGlobalLong);
|
||||
interpreter.installSegment5 (44, new OpFetchGlobalFloat);
|
||||
interpreter.installSegment5 (59, new OpStoreMemberShort);
|
||||
interpreter.installSegment5 (60, new OpStoreMemberLong);
|
||||
interpreter.installSegment5 (61, new OpStoreMemberFloat);
|
||||
interpreter.installSegment5 (62, new OpFetchMemberShort);
|
||||
interpreter.installSegment5 (63, new OpFetchMemberLong);
|
||||
interpreter.installSegment5 (64, new OpFetchMemberFloat);
|
||||
interpreter.installSegment5 (59, new OpStoreMemberShort (false));
|
||||
interpreter.installSegment5 (60, new OpStoreMemberLong (false));
|
||||
interpreter.installSegment5 (61, new OpStoreMemberFloat (false));
|
||||
interpreter.installSegment5 (62, new OpFetchMemberShort (false));
|
||||
interpreter.installSegment5 (63, new OpFetchMemberLong (false));
|
||||
interpreter.installSegment5 (64, new OpFetchMemberFloat (false));
|
||||
interpreter.installSegment5 (65, new OpStoreMemberShort (true));
|
||||
interpreter.installSegment5 (66, new OpStoreMemberLong (true));
|
||||
interpreter.installSegment5 (67, new OpStoreMemberFloat (true));
|
||||
interpreter.installSegment5 (68, new OpFetchMemberShort (true));
|
||||
interpreter.installSegment5 (69, new OpFetchMemberLong (true));
|
||||
interpreter.installSegment5 (70, new OpFetchMemberFloat (true));
|
||||
|
||||
// math
|
||||
interpreter.installSegment5 (9, new OpAddInt<Type_Integer>);
|
||||
|
|
|
@ -208,8 +208,12 @@ namespace Interpreter
|
|||
|
||||
class OpStoreMemberShort : public Opcode0
|
||||
{
|
||||
bool mGlobal;
|
||||
|
||||
public:
|
||||
|
||||
OpStoreMemberShort (bool global) : mGlobal (global) {}
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer data = runtime[0].mInteger;
|
||||
|
@ -218,7 +222,7 @@ namespace Interpreter
|
|||
index = runtime[2].mInteger;
|
||||
std::string variable = runtime.getStringLiteral (index);
|
||||
|
||||
runtime.getContext().setMemberShort (id, variable, data);
|
||||
runtime.getContext().setMemberShort (id, variable, data, mGlobal);
|
||||
|
||||
runtime.pop();
|
||||
runtime.pop();
|
||||
|
@ -228,8 +232,12 @@ namespace Interpreter
|
|||
|
||||
class OpStoreMemberLong : public Opcode0
|
||||
{
|
||||
bool mGlobal;
|
||||
|
||||
public:
|
||||
|
||||
OpStoreMemberLong (bool global) : mGlobal (global) {}
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer data = runtime[0].mInteger;
|
||||
|
@ -238,7 +246,7 @@ namespace Interpreter
|
|||
index = runtime[2].mInteger;
|
||||
std::string variable = runtime.getStringLiteral (index);
|
||||
|
||||
runtime.getContext().setMemberLong (id, variable, data);
|
||||
runtime.getContext().setMemberLong (id, variable, data, mGlobal);
|
||||
|
||||
runtime.pop();
|
||||
runtime.pop();
|
||||
|
@ -248,8 +256,12 @@ namespace Interpreter
|
|||
|
||||
class OpStoreMemberFloat : public Opcode0
|
||||
{
|
||||
bool mGlobal;
|
||||
|
||||
public:
|
||||
|
||||
OpStoreMemberFloat (bool global) : mGlobal (global) {}
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Float data = runtime[0].mFloat;
|
||||
|
@ -258,7 +270,7 @@ namespace Interpreter
|
|||
index = runtime[2].mInteger;
|
||||
std::string variable = runtime.getStringLiteral (index);
|
||||
|
||||
runtime.getContext().setMemberFloat (id, variable, data);
|
||||
runtime.getContext().setMemberFloat (id, variable, data, mGlobal);
|
||||
|
||||
runtime.pop();
|
||||
runtime.pop();
|
||||
|
@ -268,8 +280,12 @@ namespace Interpreter
|
|||
|
||||
class OpFetchMemberShort : public Opcode0
|
||||
{
|
||||
bool mGlobal;
|
||||
|
||||
public:
|
||||
|
||||
OpFetchMemberShort (bool global) : mGlobal (global) {}
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer index = runtime[0].mInteger;
|
||||
|
@ -278,15 +294,19 @@ namespace Interpreter
|
|||
std::string variable = runtime.getStringLiteral (index);
|
||||
runtime.pop();
|
||||
|
||||
int value = runtime.getContext().getMemberShort (id, variable);
|
||||
int value = runtime.getContext().getMemberShort (id, variable, mGlobal);
|
||||
runtime[0].mInteger = value;
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchMemberLong : public Opcode0
|
||||
{
|
||||
bool mGlobal;
|
||||
|
||||
public:
|
||||
|
||||
OpFetchMemberLong (bool global) : mGlobal (global) {}
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer index = runtime[0].mInteger;
|
||||
|
@ -295,15 +315,19 @@ namespace Interpreter
|
|||
std::string variable = runtime.getStringLiteral (index);
|
||||
runtime.pop();
|
||||
|
||||
int value = runtime.getContext().getMemberLong (id, variable);
|
||||
int value = runtime.getContext().getMemberLong (id, variable, mGlobal);
|
||||
runtime[0].mInteger = value;
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchMemberFloat : public Opcode0
|
||||
{
|
||||
bool mGlobal;
|
||||
|
||||
public:
|
||||
|
||||
OpFetchMemberFloat (bool global) : mGlobal (global) {}
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer index = runtime[0].mInteger;
|
||||
|
@ -312,7 +336,7 @@ namespace Interpreter
|
|||
std::string variable = runtime.getStringLiteral (index);
|
||||
runtime.pop();
|
||||
|
||||
float value = runtime.getContext().getMemberFloat (id, variable);
|
||||
float value = runtime.getContext().getMemberFloat (id, variable, mGlobal);
|
||||
runtime[0].mFloat = value;
|
||||
}
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue