1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-24 23:09:42 +00:00

Merge branch 'openmw-29' of https://github.com/zinnschlag/openmw.git into AIFix2

This commit is contained in:
gus 2014-02-23 17:07:49 +01:00
commit 95ff869163
138 changed files with 3380 additions and 757 deletions

View file

@ -4,17 +4,16 @@ compiler:
branches: branches:
only: only:
- master - master
- next - /openmw-.*$/
before_install: before_install:
- pwd - pwd
- git submodule update --init --recursive
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - 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 - echo "yes" | sudo apt-add-repository ppa:openmw/openmw
- sudo apt-get update -qq - 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 libboost-all-dev libgtest-dev google-mock
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libqt4-dev
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libopenal-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-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 apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo mkdir /usr/src/gtest/build - sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build - cd /usr/src/gtest/build
@ -37,3 +36,9 @@ notifications:
email: email:
on_success: change on_success: change
on_failure: always on_failure: always
irc:
channels:
- "chat.freenode.net#openmw"
on_success: change
on_failure: always

View file

@ -4,40 +4,65 @@ if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") 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) endif (APPLE)
# Macros
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
include(OpenMWMacros)
# Version # Version
message(STATUS "Configuring OpenMW...")
include(GetGitRevisionDescription) set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 28)
set(OPENMW_VERSION_RELEASE 0)
get_git_tag_revision(TAGHASH --tags --max-count=1) set(OPENMW_VERSION_COMMITHASH "")
get_git_head_revision(REFSPEC COMMITHASH) set(OPENMW_VERSION_TAGHASH "")
git_describe(VERSION --tags ${TAGHASH})
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}") set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
if (MATCH)
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" OPENMW_VERSION_MAJOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_RELEASE "${VERSION}")
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
set(OPENMW_VERSION_TAGHASH "${TAGHASH}") find_package(Git)
message(STATUS "Configuring OpenMW ${OPENMW_VERSION}...") if(GIT_FOUND)
else (MATCH) include(GetGitRevisionDescription)
message(FATAL_ERROR "Failed to get valid version information from Git") get_git_tag_revision(TAGHASH --tags --max-count=1)
endif (MATCH) get_git_head_revision(REFSPEC COMMITHASH)
git_describe(VERSION --tags ${TAGHASH})
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
if(MATCH)
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}")
if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
message(FATAL_ERROR "Silly Zini forgot to update the version again...")
else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR})
set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR})
set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE})
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
message(STATUS "OpenMW version ${OPENMW_VERSION}")
else(MATCH)
message(WARNING "Failed to get valid version information from Git")
endif(MATCH)
else(GIT_FOUND)
message(WARNING "Git executable not found")
endif(GIT_FOUND)
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
# Macros
include(OpenMWMacros)
# doxygen main page # doxygen main page
@ -206,10 +231,6 @@ if (MSVC10)
set(PLATFORM_INCLUDE_DIR "") set(PLATFORM_INCLUDE_DIR "")
endif() endif()
if (APPLE)
set(Boost_USE_STATIC_LIBS ON)
endif (APPLE)
# Dependencies # Dependencies
# Fix for not visible pthreads functions for linker with glibc 2.15 # Fix for not visible pthreads functions for linker with glibc 2.15
@ -260,10 +281,15 @@ link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MY
if (APPLE) if (APPLE)
# List used Ogre plugins # List used Ogre plugins
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL}
${OGRE_Plugin_CgProgramManager_LIBRARY_REL}
${OGRE_Plugin_ParticleFX_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}}) if (${OGRE_PLUGIN_DIR_REL}})
set(OGRE_PLUGINS_REL_FOUND TRUE) set(OGRE_PLUGINS_REL_FOUND TRUE)
endif () endif ()
@ -278,8 +304,6 @@ if (APPLE)
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
endif () endif ()
#set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/")
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
"${APP_BUNDLE_DIR}/Contents/Info.plist") "${APP_BUNDLE_DIR}/Contents/Info.plist")
@ -301,7 +325,8 @@ endif()
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}") add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
if (APPLE AND OPENMW_OSX_DEPLOYMENT) 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() else()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
endif() endif()
@ -657,14 +682,14 @@ if (APPLE)
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) 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(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") 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 "") set(ABSOLUTE_PLUGINS "")
foreach (PLUGIN ${USED_OGRE_PLUGINS}) foreach (PLUGIN ${USED_OGRE_PLUGINS})
@ -672,12 +697,36 @@ if (APPLE)
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
endforeach () endforeach ()
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins") install(CODE "
install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime) set(BU_CHMOD_BUNDLE_ITEMS ON)
foreach (PLUGIN ${ABSOLUTE_PLUGINS}) include(BundleUtilities)
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) " COMPONENT Runtime)
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
endforeach () # 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 #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 "") set(DIRS "")
@ -690,6 +739,7 @@ if (APPLE)
# Current limitations: # Current limitations:
# 1. Handles only frameworks, not simple libs # 1. Handles only frameworks, not simple libs
INSTALL(CODE " INSTALL(CODE "
cmake_policy(SET CMP0009 OLD)
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES}) set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH}) set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
@ -721,11 +771,8 @@ if (APPLE)
endif() endif()
endfunction(gp_resolve_item_override) 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(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\")
" COMPONENT Runtime) " COMPONENT Runtime)
include(CPack) include(CPack)
endif (APPLE) endif (APPLE)

View file

@ -76,17 +76,20 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
QString revision(OPENMW_VERSION_COMMITHASH); QString revision(OPENMW_VERSION_COMMITHASH);
QString tag(OPENMW_VERSION_TAGHASH); QString tag(OPENMW_VERSION_TAGHASH);
if (revision == tag) { if (!revision.isEmpty() && !tag.isEmpty())
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION)); {
} else { if (revision == tag) {
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10))); versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
} } else {
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
}
// Add the compile date and time // Add the compile date and time
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
}
createIcons(); createIcons();
} }

View file

@ -24,7 +24,7 @@ opencs_units (model/world
opencs_units_noqt (model/world opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
@ -38,7 +38,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referenceablecheck birthsigncheck spellcheck referenceablecheck scriptcheck
) )
@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
scenetoolmode infocreator scenetoolmode infocreator scriptedit
) )
opencs_units (view/render opencs_units (view/render

View file

@ -210,6 +210,8 @@ int CS::Editor::run()
if (mLocal.empty()) if (mLocal.empty())
return 1; return 1;
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
// TODO: setting // TODO: setting
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem")); 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("FSAA", "0"));
params.insert(std::make_pair("vsync", "false")); params.insert(std::make_pair("vsync", "false"));
params.insert(std::make_pair("hidden", "true")); 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, &params); Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params);
hiddenWindow->setActive(false); hiddenWindow->setActive(false);
#endif
mStartup.show(); mStartup.show();

View file

@ -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 :( // SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
Application mApplication (argc, argv); Application mApplication (argc, argv);
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
OgreInit::OgreInit ogreInit; OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path? ogreInit.init("./opencsOgre.log"); // TODO log path?
#endif
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());

View file

@ -71,7 +71,10 @@ namespace CSMDoc
public: public:
Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_); Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath,
const boost::filesystem::path& resDir, bool new_);
~Document(); ~Document();

View file

@ -29,7 +29,9 @@ namespace CSMDoc
~DocumentManager(); ~DocumentManager();
Document *addDocument (const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, bool new_); Document *addDocument (const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath,
bool new_);
///< The ownership of the returned document is not transferred to the caller. ///< The ownership of the returned document is not transferred to the caller.
/// ///
/// \param new_ Do not load the last content file in \a files and instead create in an /// \param new_ Do not load the last content file in \a files and instead create in an

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

View 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

View file

@ -20,6 +20,7 @@
#include "birthsigncheck.hpp" #include "birthsigncheck.hpp"
#include "spellcheck.hpp" #include "spellcheck.hpp"
#include "referenceablecheck.hpp" #include "referenceablecheck.hpp"
#include "scriptcheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type) 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 SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mData));
} }
return mVerifier; return mVerifier;

View file

@ -26,7 +26,49 @@ namespace CSMWorld
enum Display enum Display
{ {
Display_None, //Do not use
Display_String, Display_String,
//CONCRETE TYPES STARTS HERE
Display_Skill,
Display_Class,
Display_Faction,
Display_Race,
Display_Sound,
Display_Region,
Display_Birthsign,
Display_Spell,
Display_Cell,
Display_Referenceable,
Display_Activator,
Display_Potion,
Display_Apparatus,
Display_Armor,
Display_Book,
Display_Clothing,
Display_Container,
Display_Creature,
Display_Door,
Display_Ingredient,
Display_CreatureLevelledList,
Display_ItemLevelledList,
Display_Light,
Display_Lockpick,
Display_Miscellaneous,
Display_Npc,
Display_Probe,
Display_Repair,
Display_Static,
Display_Weapon,
Display_Reference,
Display_Filter,
Display_Topic,
Display_Journal,
Display_TopicInfo,
Display_JournalInfo,
Display_Scene,
//CONCRETE TYPES ENDS HERE
Display_Integer, Display_Integer,
Display_Float, Display_Float,
Display_Var, Display_Var,

View file

@ -373,7 +373,7 @@ namespace CSMWorld
SkillsColumn (int index, bool typePrefix = false, bool major = false) SkillsColumn (int index, bool typePrefix = false, bool major = false)
: Column<ESXRecordT> ((typePrefix ? ( : Column<ESXRecordT> ((typePrefix ? (
major ? Columns::ColumnId_MajorSkill1 : Columns::ColumnId_MinorSkill1) : major ? Columns::ColumnId_MajorSkill1 : Columns::ColumnId_MinorSkill1) :
Columns::ColumnId_Skill1) + index, ColumnBase::Display_String), Columns::ColumnId_Skill1) + index, ColumnBase::Display_Skill),
mIndex (index), mMajor (major) mIndex (index), mMajor (major)
{} {}
@ -598,7 +598,7 @@ namespace CSMWorld
struct SoundFileColumn : public Column<ESXRecordT> struct SoundFileColumn : public Column<ESXRecordT>
{ {
SoundFileColumn() SoundFileColumn()
: Column<ESXRecordT> (Columns::ColumnId_SoundFile, ColumnBase::Display_String) : Column<ESXRecordT> (Columns::ColumnId_SoundFile, ColumnBase::Display_Sound)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -811,7 +811,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct CellColumn : public Column<ESXRecordT> struct CellColumn : public Column<ESXRecordT>
{ {
CellColumn() : Column<ESXRecordT> (Columns::ColumnId_Cell, ColumnBase::Display_String) {} CellColumn() : Column<ESXRecordT> (Columns::ColumnId_Cell, ColumnBase::Display_Cell) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -890,7 +890,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct OwnerColumn : public Column<ESXRecordT> struct OwnerColumn : public Column<ESXRecordT>
{ {
OwnerColumn() : Column<ESXRecordT> (Columns::ColumnId_Owner, ColumnBase::Display_String) {} OwnerColumn() : Column<ESXRecordT> (Columns::ColumnId_Owner, ColumnBase::Display_Npc) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -915,7 +915,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct SoulColumn : public Column<ESXRecordT> struct SoulColumn : public Column<ESXRecordT>
{ {
SoulColumn() : Column<ESXRecordT> (Columns::ColumnId_Soul, ColumnBase::Display_String) {} SoulColumn() : Column<ESXRecordT> (Columns::ColumnId_Soul, ColumnBase::Display_Creature) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -940,7 +940,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct FactionColumn : public Column<ESXRecordT> struct FactionColumn : public Column<ESXRecordT>
{ {
FactionColumn() : Column<ESXRecordT> (Columns::ColumnId_Faction, ColumnBase::Display_String) {} FactionColumn() : Column<ESXRecordT> (Columns::ColumnId_Faction, ColumnBase::Display_Faction) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1090,7 +1090,7 @@ namespace CSMWorld
struct TeleportCellColumn : public Column<ESXRecordT> struct TeleportCellColumn : public Column<ESXRecordT>
{ {
TeleportCellColumn() TeleportCellColumn()
: Column<ESXRecordT> (Columns::ColumnId_TeleportCell, ColumnBase::Display_String) : Column<ESXRecordT> (Columns::ColumnId_TeleportCell, ColumnBase::Display_Cell)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -1146,7 +1146,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct KeyColumn : public Column<ESXRecordT> struct KeyColumn : public Column<ESXRecordT>
{ {
KeyColumn() : Column<ESXRecordT> (Columns::ColumnId_Key, ColumnBase::Display_String) {} KeyColumn() : Column<ESXRecordT> (Columns::ColumnId_Key, ColumnBase::Display_Miscellaneous) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1485,7 +1485,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct RaceColumn : public Column<ESXRecordT> struct RaceColumn : public Column<ESXRecordT>
{ {
RaceColumn() : Column<ESXRecordT> (Columns::ColumnId_Race, ColumnBase::Display_String) {} RaceColumn() : Column<ESXRecordT> (Columns::ColumnId_Race, ColumnBase::Display_Race) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1510,7 +1510,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct ClassColumn : public Column<ESXRecordT> struct ClassColumn : public Column<ESXRecordT>
{ {
ClassColumn() : Column<ESXRecordT> (Columns::ColumnId_Class, ColumnBase::Display_String) {} ClassColumn() : Column<ESXRecordT> (Columns::ColumnId_Class, ColumnBase::Display_Class) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1535,7 +1535,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct PcFactionColumn : public Column<ESXRecordT> struct PcFactionColumn : public Column<ESXRecordT>
{ {
PcFactionColumn() : Column<ESXRecordT> (Columns::ColumnId_PcFaction, ColumnBase::Display_String) {} PcFactionColumn() : Column<ESXRecordT> (Columns::ColumnId_PcFaction, ColumnBase::Display_Faction) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {

View file

@ -33,7 +33,9 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
: QSortFilterProxyModel (parent) : QSortFilterProxyModel (parent)
{} {
setSortCaseSensitivity (Qt::CaseInsensitive);
}
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
{ {

View file

@ -59,7 +59,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Name, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Name, ColumnBase::Display_String));
nameColumns.mName = &mColumns.back(); nameColumns.mName = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Script, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Script, ColumnBase::Display_Script));
nameColumns.mScript = &mColumns.back(); nameColumns.mScript = &mColumns.back();
InventoryColumns inventoryColumns (nameColumns); InventoryColumns inventoryColumns (nameColumns);
@ -214,10 +214,10 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound));
const RefIdColumn *openSound = &mColumns.back(); const RefIdColumn *openSound = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_CloseSound, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_CloseSound, ColumnBase::Display_Sound));
const RefIdColumn *closeSound = &mColumns.back(); const RefIdColumn *closeSound = &mColumns.back();
LightColumns lightColumns (inventoryColumns); LightColumns lightColumns (inventoryColumns);
@ -231,7 +231,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Integer)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Integer));
lightColumns.mColor = &mColumns.back(); lightColumns.mColor = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_Sound));
lightColumns.mSound = &mColumns.back(); lightColumns.mSound = &mColumns.back();
static const struct static const struct
@ -263,13 +263,13 @@ CSMWorld::RefIdCollection::RefIdCollection()
NpcColumns npcColumns (actorsColumns); NpcColumns npcColumns (actorsColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Race, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Race, ColumnBase::Display_Race));
npcColumns.mRace = &mColumns.back(); npcColumns.mRace = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_Class));
npcColumns.mClass = &mColumns.back(); npcColumns.mClass = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
npcColumns.mFaction = &mColumns.back(); npcColumns.mFaction = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String));
@ -432,7 +432,7 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count)
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) 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 int CSMWorld::RefIdCollection::searchId (const std::string& id) const
@ -467,7 +467,7 @@ void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
int index = mData.getAppendIndex (type); int index = mData.getAppendIndex (type);
mData.appendRecord (type, id); mData.appendRecord (type, id, false);
mData.getRecord (mData.globalToLocalIndex (index)).assign (record); mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
} }
@ -515,7 +515,7 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers
{ {
// new record // new record
int index = mData.getAppendIndex (type); int index = mData.getAppendIndex (type);
mData.appendRecord (type, id); mData.appendRecord (type, id, base);
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);

View file

@ -131,7 +131,7 @@ CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index)
return iter->second->getRecord (index.first); 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 = std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (type); mRecordContainers.find (type);
@ -139,7 +139,7 @@ void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::strin
if (iter==mRecordContainers.end()) if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type"); 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), mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
LocalIndex (iter->second->getSize()-1, type))); LocalIndex (iter->second->getSize()-1, type)));

View file

@ -45,7 +45,7 @@ namespace CSMWorld
virtual RecordBase& getRecord (int index)= 0; 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 insertRecord (RecordBase& record) = 0;
@ -69,7 +69,7 @@ namespace CSMWorld
virtual RecordBase& getRecord (int index); 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 insertRecord (RecordBase& record);
@ -108,12 +108,15 @@ namespace CSMWorld
} }
template<typename RecordT> 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<RecordT> record;
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
record.mBase.mId = id;
record.mModified.mId = id; record.mModified.mId = id;
record.mModified.blank(); (base ? record.mBase : record.mModified).blank();
record.mState = RecordBase::State_ModifiedOnly;
mContainer.push_back (record); mContainer.push_back (record);
} }
@ -213,7 +216,7 @@ namespace CSMWorld
RecordBase& getRecord (const LocalIndex& index); 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; int getAppendIndex (UniversalId::Type type) const;

View file

@ -5,23 +5,92 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/compiler/quickfileparser.hpp>
#include <components/compiler/nullerrorhandler.hpp>
#include <components/compiler/scanner.hpp>
#include "data.hpp" #include "data.hpp"
CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {} CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
bool CSMWorld::ScriptContext::canDeclareLocals() const bool CSMWorld::ScriptContext::canDeclareLocals() const
{ {
return false; return true;
} }
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const 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 ' '; 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 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(); mIds = mData.getIds();
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase); std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
std::sort (mIds.begin(), mIds.end());
mIdsUpdated = true; 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)); 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() void CSMWorld::ScriptContext::invalidateIds()
{ {
mIdsUpdated = false; mIdsUpdated = false;
} }
void CSMWorld::ScriptContext::clear()
{
mIds.clear();
mIdsUpdated = false;
mLocals.clear();
}

View file

@ -3,8 +3,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include <components/compiler/context.hpp> #include <components/compiler/context.hpp>
#include <components/compiler/locals.hpp>
namespace CSMWorld namespace CSMWorld
{ {
@ -15,6 +17,7 @@ namespace CSMWorld
const Data& mData; const Data& mData;
mutable std::vector<std::string> mIds; mutable std::vector<std::string> mIds;
mutable bool mIdsUpdated; mutable bool mIdsUpdated;
mutable std::map<std::string, Compiler::Locals> mLocals;
public: public:
@ -26,13 +29,23 @@ namespace CSMWorld
virtual char getGlobalType (const std::string& name) const; virtual char getGlobalType (const std::string& name) const;
///< 'l: long, 's': short, 'f': float, ' ': does not exist. ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. 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; virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced? ///< 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 invalidateIds();
void clear();
///< Remove all cached data.
}; };
} }

View file

@ -0,0 +1,446 @@
#include "tablemimedata.hpp"
#include <string>
#include "universalid.hpp"
#include "columnbase.hpp"
CSMWorld::TableMimeData::TableMimeData (UniversalId id, const CSMDoc::Document& document) :
mDocument(document)
{
mUniversalId.push_back (id);
mObjectsFormats << QString::fromStdString ("tabledata/" + id.getTypeName());
}
CSMWorld::TableMimeData::TableMimeData (std::vector< CSMWorld::UniversalId >& id, const CSMDoc::Document& document) :
mUniversalId (id), mDocument(document)
{
for (std::vector<UniversalId>::iterator it (mUniversalId.begin()); it != mUniversalId.end(); ++it)
{
mObjectsFormats << QString::fromStdString ("tabledata/" + it->getTypeName());
}
}
QStringList CSMWorld::TableMimeData::formats() const
{
return mObjectsFormats;
}
CSMWorld::TableMimeData::~TableMimeData()
{
}
std::string CSMWorld::TableMimeData::getIcon() const
{
if (mUniversalId.empty())
{
throw ("TableMimeData holds no UniversalId");
}
std::string tmpIcon;
bool firstIteration = true;
for (unsigned i = 0; i < mUniversalId.size(); ++i)
{
if (firstIteration)
{
firstIteration = false;
tmpIcon = mUniversalId[i].getIcon();
continue;
}
if (tmpIcon != mUniversalId[i].getIcon())
{
return ":/multitype.png"; //icon stolen from gnome
}
tmpIcon = mUniversalId[i].getIcon();
}
return mUniversalId.begin()->getIcon(); //All objects are of the same type;
}
std::vector< CSMWorld::UniversalId > CSMWorld::TableMimeData::getData() const
{
return mUniversalId;
}
bool CSMWorld::TableMimeData::holdsType (CSMWorld::UniversalId::Type type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == type)
{
return true;
}
}
return false;
}
bool CSMWorld::TableMimeData::holdsType (CSMWorld::ColumnBase::Display type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == convertEnums (type))
{
return true;
}
}
return false;
}
CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::UniversalId::Type type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == type)
{
return *it;
}
}
throw ("TableMimeData object does not hold object of the seeked type");
}
CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnBase::Display type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == convertEnums (type))
{
return *it;
}
}
throw ("TableMimeData object does not hold object of the seeked type");
}
bool CSMWorld::TableMimeData::fromDocument (const CSMDoc::Document& document) const
{
return &document == &mDocument;
}
CSMWorld::UniversalId::Type CSMWorld::TableMimeData::convertEnums (CSMWorld::ColumnBase::Display type)
{
switch (type)
{
case CSMWorld::ColumnBase::Display_Race:
return CSMWorld::UniversalId::Type_Race;
case CSMWorld::ColumnBase::Display_Skill:
return CSMWorld::UniversalId::Type_Skill;
case CSMWorld::ColumnBase::Display_Class:
return CSMWorld::UniversalId::Type_Class;
case CSMWorld::ColumnBase::Display_Faction:
return CSMWorld::UniversalId::Type_Faction;
case CSMWorld::ColumnBase::Display_Sound:
return CSMWorld::UniversalId::Type_Sound;
case CSMWorld::ColumnBase::Display_Region:
return CSMWorld::UniversalId::Type_Region;
case CSMWorld::ColumnBase::Display_Birthsign:
return CSMWorld::UniversalId::Type_Birthsign;
case CSMWorld::ColumnBase::Display_Spell:
return CSMWorld::UniversalId::Type_Spell;
case CSMWorld::ColumnBase::Display_Cell:
return CSMWorld::UniversalId::Type_Cell;
case CSMWorld::ColumnBase::Display_Referenceable:
return CSMWorld::UniversalId::Type_Referenceable;
case CSMWorld::ColumnBase::Display_Activator:
return CSMWorld::UniversalId::Type_Activator;
case CSMWorld::ColumnBase::Display_Potion:
return CSMWorld::UniversalId::Type_Potion;
case CSMWorld::ColumnBase::Display_Apparatus:
return CSMWorld::UniversalId::Type_Apparatus;
case CSMWorld::ColumnBase::Display_Armor:
return CSMWorld::UniversalId::Type_Armor;
case CSMWorld::ColumnBase::Display_Book:
return CSMWorld::UniversalId::Type_Book;
case CSMWorld::ColumnBase::Display_Clothing:
return CSMWorld::UniversalId::Type_Clothing;
case CSMWorld::ColumnBase::Display_Container:
return CSMWorld::UniversalId::Type_Container;
case CSMWorld::ColumnBase::Display_Creature:
return CSMWorld::UniversalId::Type_Creature;
case CSMWorld::ColumnBase::Display_Door:
return CSMWorld::UniversalId::Type_Door;
case CSMWorld::ColumnBase::Display_Ingredient:
return CSMWorld::UniversalId::Type_Ingredient;
case CSMWorld::ColumnBase::Display_CreatureLevelledList:
return CSMWorld::UniversalId::Type_CreatureLevelledList;
case CSMWorld::ColumnBase::Display_ItemLevelledList:
return CSMWorld::UniversalId::Type_ItemLevelledList;
case CSMWorld::ColumnBase::Display_Light:
return CSMWorld::UniversalId::Type_Light;
case CSMWorld::ColumnBase::Display_Lockpick:
return CSMWorld::UniversalId::Type_Lockpick;
case CSMWorld::ColumnBase::Display_Miscellaneous:
return CSMWorld::UniversalId::Type_Miscellaneous;
case CSMWorld::ColumnBase::Display_Npc:
return CSMWorld::UniversalId::Type_Npc;
case CSMWorld::ColumnBase::Display_Probe:
return CSMWorld::UniversalId::Type_Probe;
case CSMWorld::ColumnBase::Display_Repair:
return CSMWorld::UniversalId::Type_Repair;
case CSMWorld::ColumnBase::Display_Static:
return CSMWorld::UniversalId::Type_Static;
case CSMWorld::ColumnBase::Display_Weapon:
return CSMWorld::UniversalId::Type_Weapon;
case CSMWorld::ColumnBase::Display_Reference:
return CSMWorld::UniversalId::Type_Reference;
case CSMWorld::ColumnBase::Display_Filter:
return CSMWorld::UniversalId::Type_Filter;
case CSMWorld::ColumnBase::Display_Topic:
return CSMWorld::UniversalId::Type_Topic;
case CSMWorld::ColumnBase::Display_Journal:
return CSMWorld::UniversalId::Type_Journal;
case CSMWorld::ColumnBase::Display_TopicInfo:
return CSMWorld::UniversalId::Type_TopicInfo;
case CSMWorld::ColumnBase::Display_JournalInfo:
return CSMWorld::UniversalId::Type_JournalInfo;
case CSMWorld::ColumnBase::Display_Scene:
return CSMWorld::UniversalId::Type_Scene;
case CSMWorld::ColumnBase::Display_Script:
return CSMWorld::UniversalId::Type_Script;
default:
return CSMWorld::UniversalId::Type_None;
}
}
CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::UniversalId::Type type)
{
switch (type)
{
case CSMWorld::UniversalId::Type_Race:
return CSMWorld::ColumnBase::Display_Race;
case CSMWorld::UniversalId::Type_Skill:
return CSMWorld::ColumnBase::Display_Skill;
case CSMWorld::UniversalId::Type_Class:
return CSMWorld::ColumnBase::Display_Class;
case CSMWorld::UniversalId::Type_Faction:
return CSMWorld::ColumnBase::Display_Faction;
case CSMWorld::UniversalId::Type_Sound:
return CSMWorld::ColumnBase::Display_Sound;
case CSMWorld::UniversalId::Type_Region:
return CSMWorld::ColumnBase::Display_Region;
case CSMWorld::UniversalId::Type_Birthsign:
return CSMWorld::ColumnBase::Display_Birthsign;
case CSMWorld::UniversalId::Type_Spell:
return CSMWorld::ColumnBase::Display_Spell;
case CSMWorld::UniversalId::Type_Cell:
return CSMWorld::ColumnBase::Display_Cell;
case CSMWorld::UniversalId::Type_Referenceable:
return CSMWorld::ColumnBase::Display_Referenceable;
case CSMWorld::UniversalId::Type_Activator:
return CSMWorld::ColumnBase::Display_Activator;
case CSMWorld::UniversalId::Type_Potion:
return CSMWorld::ColumnBase::Display_Potion;
case CSMWorld::UniversalId::Type_Apparatus:
return CSMWorld::ColumnBase::Display_Apparatus;
case CSMWorld::UniversalId::Type_Armor:
return CSMWorld::ColumnBase::Display_Armor;
case CSMWorld::UniversalId::Type_Book:
return CSMWorld::ColumnBase::Display_Book;
case CSMWorld::UniversalId::Type_Clothing:
return CSMWorld::ColumnBase::Display_Clothing;
case CSMWorld::UniversalId::Type_Container:
return CSMWorld::ColumnBase::Display_Container;
case CSMWorld::UniversalId::Type_Creature:
return CSMWorld::ColumnBase::Display_Creature;
case CSMWorld::UniversalId::Type_Door:
return CSMWorld::ColumnBase::Display_Door;
case CSMWorld::UniversalId::Type_Ingredient:
return CSMWorld::ColumnBase::Display_Ingredient;
case CSMWorld::UniversalId::Type_CreatureLevelledList:
return CSMWorld::ColumnBase::Display_CreatureLevelledList;
case CSMWorld::UniversalId::Type_ItemLevelledList:
return CSMWorld::ColumnBase::Display_ItemLevelledList;
case CSMWorld::UniversalId::Type_Light:
return CSMWorld::ColumnBase::Display_Light;
case CSMWorld::UniversalId::Type_Lockpick:
return CSMWorld::ColumnBase::Display_Lockpick;
case CSMWorld::UniversalId::Type_Miscellaneous:
return CSMWorld::ColumnBase::Display_Miscellaneous;
case CSMWorld::UniversalId::Type_Npc:
return CSMWorld::ColumnBase::Display_Npc;
case CSMWorld::UniversalId::Type_Probe:
return CSMWorld::ColumnBase::Display_Probe;
case CSMWorld::UniversalId::Type_Repair:
return CSMWorld::ColumnBase::Display_Repair;
case CSMWorld::UniversalId::Type_Static:
return CSMWorld::ColumnBase::Display_Static;
case CSMWorld::UniversalId::Type_Weapon:
return CSMWorld::ColumnBase::Display_Weapon;
case CSMWorld::UniversalId::Type_Reference:
return CSMWorld::ColumnBase::Display_Reference;
case CSMWorld::UniversalId::Type_Filter:
return CSMWorld::ColumnBase::Display_Filter;
case CSMWorld::UniversalId::Type_Topic:
return CSMWorld::ColumnBase::Display_Topic;
case CSMWorld::UniversalId::Type_Journal:
return CSMWorld::ColumnBase::Display_Journal;
case CSMWorld::UniversalId::Type_TopicInfo:
return CSMWorld::ColumnBase::Display_TopicInfo;
case CSMWorld::UniversalId::Type_JournalInfo:
return CSMWorld::ColumnBase::Display_JournalInfo;
case CSMWorld::UniversalId::Type_Scene:
return CSMWorld::ColumnBase::Display_Scene;
case CSMWorld::UniversalId::Type_Script:
return CSMWorld::ColumnBase::Display_Script;
default:
return CSMWorld::ColumnBase::Display_None;
}
}

View file

@ -0,0 +1,63 @@
#ifndef TABLEMIMEDATA_H
#define TABLEMIMEDATA_H
#include <vector>
#include <QtCore/QMimeData>
#include <QStringList>
#include "universalid.hpp"
#include "columnbase.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
/// \brief Subclass of QmimeData, augmented to contain and transport UniversalIds.
///
/// This class provides way to construct mimedata object holding the universalid copy
/// Universalid is used in the majority of the tables to store type, id, argument types.
/// This way universalid grants a way to retrive record from the concrete table.
/// Please note, that tablemimedata object can hold multiple universalIds in the vector.
class TableMimeData : public QMimeData
{
public:
TableMimeData(UniversalId id, const CSMDoc::Document& document);
TableMimeData(std::vector<UniversalId>& id, const CSMDoc::Document& document);
~TableMimeData();
virtual QStringList formats() const;
std::string getIcon() const;
std::vector<UniversalId> getData() const;
bool holdsType(UniversalId::Type type) const;
bool holdsType(CSMWorld::ColumnBase::Display type) const;
bool fromDocument(const CSMDoc::Document& document) const;
UniversalId returnMatching(UniversalId::Type type) const;
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type);
private:
std::vector<UniversalId> mUniversalId;
QStringList mObjectsFormats;
const CSMDoc::Document& mDocument;
};
}
#endif // TABLEMIMEDATA_H

View file

@ -4,6 +4,7 @@
#include <ostream> #include <ostream>
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include <iostream>
namespace namespace
{ {
@ -186,7 +187,6 @@ CSMWorld::UniversalId::UniversalId (Type type, const std::string& id)
mClass = sIdArg[i].mClass; mClass = sIdArg[i].mClass;
return; return;
} }
throw std::logic_error ("invalid ID argument UniversalId type"); throw std::logic_error ("invalid ID argument UniversalId type");
} }

View file

@ -2,6 +2,8 @@
#include "editwidget.hpp" #include "editwidget.hpp"
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QString>
#include <QApplication>
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
@ -56,3 +58,146 @@ void CSVFilter::EditWidget::filterRowsInserted (const QModelIndex& parent, int s
{ {
textChanged (text()); textChanged (text());
} }
void CSVFilter::EditWidget::createFilterRequest (std::vector< std::pair< std::string, std::vector< std::string > > >& filterSource,
Qt::DropAction action)
{
const unsigned count = filterSource.size();
bool multipleElements = false;
switch (count) //setting multipleElements;
{
case 0: //empty
return; //nothing to do here
case 1: //only single
multipleElements = false;
break;
default:
multipleElements = true;
break;
}
Qt::KeyboardModifiers key = QApplication::keyboardModifiers();
QString oldContent (text());
bool replaceMode = false;
std::string orAnd;
switch (key) //setting replaceMode and string used to glue expressions
{
case Qt::ShiftModifier:
orAnd = "!or(";
replaceMode = false;
break;
case Qt::ControlModifier:
orAnd = "!and(";
replaceMode = false;
break;
default:
replaceMode = true;
break;
}
if (oldContent.isEmpty() || !oldContent.contains (QRegExp ("^!.*$", Qt::CaseInsensitive))) //if line edit is empty or it does not contain one shot filter go into replace mode
{
replaceMode = true;
}
if (!replaceMode)
{
oldContent.remove ('!');
}
std::stringstream ss;
if (multipleElements)
{
if (replaceMode)
{
ss<<"!or(";
} else {
ss << orAnd << oldContent.toStdString() << ',';
}
for (unsigned i = 0; i < count; ++i)
{
ss<<generateFilter (filterSource[i]);
if (i+1 != count)
{
ss<<", ";
}
}
ss<<')';
} else {
if (!replaceMode)
{
ss << orAnd << oldContent.toStdString() <<',';
} else {
ss<<'!';
}
ss << generateFilter (filterSource[0]);
if (!replaceMode)
{
ss<<')';
}
}
if (ss.str().length() >4)
{
clear();
insert (QString::fromUtf8(ss.str().c_str()));
}
}
std::string CSVFilter::EditWidget::generateFilter (std::pair< std::string, std::vector< std::string > >& seekedString) const
{
const unsigned columns = seekedString.second.size();
bool multipleColumns = false;
switch (columns)
{
case 0: //empty
return ""; //no column to filter
case 1: //one column to look for
multipleColumns = false;
break;
default:
multipleColumns = true;
break;
}
std::stringstream ss;
if (multipleColumns)
{
ss<<"or(";
for (unsigned i = 0; i < columns; ++i)
{
ss<<"string("<<'"'<<seekedString.second[i]<<'"'<<','<<'"'<<seekedString.first<<'"'<<')';
if (i+1 != columns)
ss<<',';
}
ss<<')';
} else {
ss<<"string"<<'('<<'"'<<seekedString.second[0]<<"\","<<'"'<<seekedString.first<<"\")";
}
return ss.str();
}
void CSVFilter::EditWidget::useFilterRequest (const std::string& idOfFilter)
{
clear();
insert(QString::fromUtf8(idOfFilter.c_str()));
}

View file

@ -5,6 +5,7 @@
#include <QLineEdit> #include <QLineEdit>
#include <QPalette> #include <QPalette>
#include <qt4/QtCore/qnamespace.h>
#include "../../model/filter/parser.hpp" #include "../../model/filter/parser.hpp"
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
@ -33,6 +34,9 @@ namespace CSVFilter
void filterChanged (boost::shared_ptr<CSMFilter::Node> filter); void filterChanged (boost::shared_ptr<CSMFilter::Node> filter);
private:
std::string generateFilter(std::pair<std::string, std::vector<std::string> >& seekedString) const;
private slots: private slots:
void textChanged (const QString& text); void textChanged (const QString& text);
@ -42,6 +46,11 @@ namespace CSVFilter
void filterRowsRemoved (const QModelIndex& parent, int start, int end); void filterRowsRemoved (const QModelIndex& parent, int start, int end);
void filterRowsInserted (const QModelIndex& parent, int start, int end); void filterRowsInserted (const QModelIndex& parent, int start, int end);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
}; };
} }

View file

@ -2,9 +2,12 @@
#include "filterbox.hpp" #include "filterbox.hpp"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QDragEnterEvent>
#include "recordfilterbox.hpp" #include "recordfilterbox.hpp"
#include <apps/opencs/model/world/tablemimedata.hpp>
CSVFilter::FilterBox::FilterBox (CSMWorld::Data& data, QWidget *parent) CSVFilter::FilterBox::FilterBox (CSMWorld::Data& data, QWidget *parent)
: QWidget (parent) : QWidget (parent)
{ {
@ -21,4 +24,27 @@ CSVFilter::FilterBox::FilterBox (CSMWorld::Data& data, QWidget *parent)
connect (recordFilterBox, connect (recordFilterBox,
SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)), SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)),
this, SIGNAL (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>))); this, SIGNAL (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>)));
connect(this, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)),
recordFilterBox, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)));
connect(this, SIGNAL(useFilterRequest(const std::string&)), recordFilterBox, SIGNAL(useFilterRequest(const std::string&)));
setAcceptDrops(true);
}
void CSVFilter::FilterBox::dropEvent (QDropEvent* event)
{
std::vector<CSMWorld::UniversalId> data = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData())->getData();
emit recordDropped(data, event->proposedAction());
}
void CSVFilter::FilterBox::dragEnterEvent (QDragEnterEvent* event)
{
event->acceptProposedAction();
}
void CSVFilter::FilterBox::dragMoveEvent (QDragMoveEvent* event)
{
event->accept();
} }

View file

@ -1,9 +1,13 @@
#ifndef CSV_FILTER_FILTERBOX_H #ifndef CSV_FILTER_FILTERBOX_H
#define CSV_FILTER_FILTERBOX_H #define CSV_FILTER_FILTERBOX_H
#include <vector>
#include <QWidget> #include <QWidget>
#include <qt4/QtCore/qnamespace.h>
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
#include "../../model/world/universalid.hpp"
namespace CSMWorld namespace CSMWorld
{ {
@ -16,6 +20,12 @@ namespace CSVFilter
{ {
Q_OBJECT Q_OBJECT
void dragEnterEvent (QDragEnterEvent* event);
void dropEvent (QDropEvent* event);
void dragMoveEvent(QDragMoveEvent *event);
public: public:
FilterBox (CSMWorld::Data& data, QWidget *parent = 0); FilterBox (CSMWorld::Data& data, QWidget *parent = 0);
@ -23,8 +33,13 @@ namespace CSVFilter
signals: signals:
void recordFilterChanged (boost::shared_ptr<CSMFilter::Node> filter); void recordFilterChanged (boost::shared_ptr<CSMFilter::Node> filter);
void recordDropped (std::vector<CSMWorld::UniversalId>& types, Qt::DropAction action);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
}; };
} }
#endif #endif

View file

@ -24,4 +24,9 @@ CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *pare
connect ( connect (
editWidget, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)), editWidget, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)),
this, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>))); this, SIGNAL (filterChanged (boost::shared_ptr<CSMFilter::Node>)));
connect(this, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)),
editWidget, SLOT(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)));
connect(this, SIGNAL(useFilterRequest(const std::string&)), editWidget, SLOT(useFilterRequest(const std::string&)));
} }

View file

@ -4,6 +4,7 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <QWidget> #include <QWidget>
#include <qt4/QtCore/qnamespace.h>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -27,6 +28,9 @@ namespace CSVFilter
signals: signals:
void filterChanged (boost::shared_ptr<CSMFilter::Node> filter); void filterChanged (boost::shared_ptr<CSMFilter::Node> filter);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
}; };
} }

View file

@ -67,6 +67,10 @@ namespace CSVRender
params.insert(std::make_pair("title", windowTitle.str())); params.insert(std::make_pair("title", windowTitle.str()));
params.insert(std::make_pair("FSAA", "0")); // TODO setting params.insert(std::make_pair("FSAA", "0")); // TODO setting
params.insert(std::make_pair("vsync", "false")); // 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, &params); mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, &params);
mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1)); mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1));

View file

@ -43,12 +43,26 @@ toolbar->addTool (new SceneToolMode (toolbar));
toolbar->addTool (new SceneToolMode (toolbar)); toolbar->addTool (new SceneToolMode (toolbar));
layout2->addWidget (toolbar, 0); layout2->addWidget (toolbar, 0);
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this); CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
layout2->addWidget (sceneWidget, 1); layout2->addWidget (sceneWidget, 1);
layout->insertLayout (0, layout2, 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); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);

View file

@ -0,0 +1,88 @@
#include "scriptedit.hpp"
#include <algorithm>
#include <QDragEnterEvent>
#include <QRegExp>
#include <QString>
#include "../../model/world/universalid.hpp"
#include "../../model/world/tablemimedata.hpp"
CSVWorld::ScriptEdit::ScriptEdit (QWidget* parent, const CSMDoc::Document& document) :
QTextEdit (parent),
mDocument (document),
mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive)
{
mAllowedTypes <<CSMWorld::UniversalId::Type_Journal
<<CSMWorld::UniversalId::Type_Global
<<CSMWorld::UniversalId::Type_Topic
<<CSMWorld::UniversalId::Type_Sound
<<CSMWorld::UniversalId::Type_Spell
<<CSMWorld::UniversalId::Type_Cell
<<CSMWorld::UniversalId::Type_Referenceable
<<CSMWorld::UniversalId::Type_Activator
<<CSMWorld::UniversalId::Type_Potion
<<CSMWorld::UniversalId::Type_Apparatus
<<CSMWorld::UniversalId::Type_Armor
<<CSMWorld::UniversalId::Type_Book
<<CSMWorld::UniversalId::Type_Clothing
<<CSMWorld::UniversalId::Type_Container
<<CSMWorld::UniversalId::Type_Creature
<<CSMWorld::UniversalId::Type_Door
<<CSMWorld::UniversalId::Type_Ingredient
<<CSMWorld::UniversalId::Type_CreatureLevelledList
<<CSMWorld::UniversalId::Type_ItemLevelledList
<<CSMWorld::UniversalId::Type_Light
<<CSMWorld::UniversalId::Type_Lockpick
<<CSMWorld::UniversalId::Type_Miscellaneous
<<CSMWorld::UniversalId::Type_Npc
<<CSMWorld::UniversalId::Type_Probe
<<CSMWorld::UniversalId::Type_Repair
<<CSMWorld::UniversalId::Type_Static
<<CSMWorld::UniversalId::Type_Weapon;
}
void CSVWorld::ScriptEdit::dragEnterEvent (QDragEnterEvent* event)
{
setTextCursor (cursorForPosition (event->pos()));
event->acceptProposedAction();
}
void CSVWorld::ScriptEdit::dragMoveEvent (QDragMoveEvent* event)
{
setTextCursor (cursorForPosition (event->pos()));
event->accept();
}
void CSVWorld::ScriptEdit::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
setTextCursor (cursorForPosition (event->pos()));
if (mime->fromDocument (mDocument))
{
std::vector<CSMWorld::UniversalId> records (mime->getData());
for (std::vector<CSMWorld::UniversalId>::iterator it = records.begin(); it != records.end(); ++it)
{
if (mAllowedTypes.contains (it->getType()))
{
if (stringNeedsQuote(it->getId()))
{
insertPlainText(QString::fromStdString ('"' + it->getId() + '"'));
} else {
insertPlainText(QString::fromStdString (it->getId()));
}
}
}
}
}
bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const
{
const QString string(QString::fromStdString(id)); //<regex> is only for c++11, so let's use qregexp for now.
//I'm not quite sure when do we need to put quotes. To be safe we will use quotes for anything other than…
return !(string.contains(mWhiteListQoutes));
}

View file

@ -0,0 +1,39 @@
#ifndef SCRIPTEDIT_H
#define SCRIPTEDIT_H
#include <qtextedit.h>
#include <QVector>
#include "../../model/world/universalid.hpp"
class QWidget;
class QRegExp;
namespace CSMDoc
{
class Document;
}
namespace CSVWorld
{
class ScriptEdit : public QTextEdit
{
Q_OBJECT
public:
ScriptEdit (QWidget* parent, const CSMDoc::Document& document);
private:
QVector<CSMWorld::UniversalId::Type> mAllowedTypes;
const CSMDoc::Document& mDocument;
const QRegExp mWhiteListQoutes;
void dragEnterEvent (QDragEnterEvent* event);
void dropEvent (QDropEvent* event);
void dragMoveEvent (QDragMoveEvent* event);
bool stringNeedsQuote(const std::string& id) const;
};
}
#endif // SCRIPTEDIT_H

View file

@ -13,6 +13,7 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "scripthighlighter.hpp" #include "scripthighlighter.hpp"
#include "scriptedit.hpp"
CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view)
{ {
@ -27,7 +28,7 @@ CSVWorld::ScriptSubView::ChangeLock::~ChangeLock()
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) : SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0)
{ {
setWidget (mEditor = new QTextEdit (this)); setWidget (mEditor = new ScriptEdit (this, mDocument));
mEditor->setAcceptRichText (false); mEditor->setAcceptRichText (false);
mEditor->setLineWrapMode (QTextEdit::NoWrap); mEditor->setLineWrapMode (QTextEdit::NoWrap);

View file

@ -4,8 +4,11 @@
#include <QHeaderView> #include <QHeaderView>
#include <QAction> #include <QAction>
#include <QApplication>
#include <QMenu> #include <QMenu>
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QString>
#include <QtCore/qnamespace.h>
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
@ -13,6 +16,8 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp" #include "../../model/world/record.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include "util.hpp" #include "util.hpp"
@ -88,7 +93,7 @@ std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
QModelIndexList selectedRows = selectionModel()->selectedRows(); QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter) ++iter)
{ {
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)); QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
@ -158,8 +163,8 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
} }
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
bool createAndDelete, bool sorting) bool createAndDelete, bool sorting, const CSMDoc::Document& document)
: mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0) : mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0), mDocument(document)
{ {
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id)); mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
@ -235,6 +240,8 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)),
this, SLOT (selectionSizeUpdate ())); this, SLOT (selectionSizeUpdate ()));
setAcceptDrops(true);
} }
void CSVWorld::Table::setEditLock (bool locked) void CSVWorld::Table::setEditLock (bool locked)
@ -432,3 +439,108 @@ void CSVWorld::Table::recordFilterChanged (boost::shared_ptr<CSMFilter::Node> fi
{ {
mProxyModel->setFilter (filter); mProxyModel->setFilter (filter);
} }
void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
if (selectedRows.size() == 0)
{
return;
}
QDrag* drag = new QDrag (this);
CSMWorld::TableMimeData* mime = NULL;
if (selectedRows.size() == 1)
{
mime = new CSMWorld::TableMimeData (getUniversalId (selectedRows.begin()->row()), mDocument);
}
else
{
std::vector<CSMWorld::UniversalId> idToDrag;
foreach (QModelIndex it, selectedRows) //I had a dream. Dream where you could use C++11 in OpenMW.
{
idToDrag.push_back (getUniversalId (it.row()));
}
mime = new CSMWorld::TableMimeData (idToDrag, mDocument);
}
drag->setMimeData (mime);
drag->setPixmap (QString::fromStdString (mime->getIcon()));
Qt::DropActions action = Qt::IgnoreAction;
switch (QApplication::keyboardModifiers())
{
case Qt::ControlModifier:
action = Qt::CopyAction;
break;
case Qt::ShiftModifier:
action = Qt::MoveAction;
break;
}
drag->exec(action);
}
}
void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::Table::dropEvent(QDropEvent *event)
{
QModelIndex index = indexAt (event->pos());
if (!index.isValid())
{
return;
}
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (mime->fromDocument (mDocument))
{
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
(mModel->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
if (mime->holdsType (display))
{
CSMWorld::UniversalId record (mime->returnMatching (display));
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
(*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str()))));
mUndoStack.push (command.release());
}
} //TODO handle drops from different document
}
void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
{
const int count = mModel->columnCount();
std::vector<std::string> titles;
for (int i = 0; i < count; ++i)
{
CSMWorld::ColumnBase::Display columndisplay = static_cast<CSMWorld::ColumnBase::Display>
(mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
if (display == columndisplay)
{
titles.push_back(mModel->headerData (i, Qt::Horizontal).toString().toStdString());
}
}
return titles;
}

View file

@ -5,8 +5,14 @@
#include <string> #include <string>
#include <QTableView> #include <QTableView>
#include <QtGui/qevent.h>
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
#include "../../model/world/columnbase.hpp"
namespace CSMDoc {
class Document;
}
class QUndoStack; class QUndoStack;
class QAction; class QAction;
@ -42,6 +48,10 @@ namespace CSVWorld
bool mEditLock; bool mEditLock;
int mRecordStatusDisplay; int mRecordStatusDisplay;
/// \brief This variable is used exclusivly for checking if dropEvents came from the same document. Most likely you
/// should NOT use it for anything else.
const CSMDoc::Document& mDocument;
private: private:
void contextMenuEvent (QContextMenuEvent *event); void contextMenuEvent (QContextMenuEvent *event);
@ -50,9 +60,19 @@ namespace CSVWorld
std::vector<std::string> listDeletableSelectedIds() const; std::vector<std::string> listDeletableSelectedIds() const;
void mouseMoveEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
public: public:
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete, bool sorting); Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete,
bool sorting, const CSMDoc::Document& document);
///< \param createAndDelete Allow creation and deletion of records. ///< \param createAndDelete Allow creation and deletion of records.
/// \param sorting Allow changing order of rows in the view via column headers. /// \param sorting Allow changing order of rows in the view via column headers.
@ -62,6 +82,8 @@ namespace CSVWorld
void updateEditorSetting (const QString &settingName, const QString &settingValue); void updateEditorSetting (const QString &settingName, const QString &settingValue);
std::vector<std::string> getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const;
signals: signals:
void editRequest (int row); void editRequest (int row);

View file

@ -2,8 +2,10 @@
#include "tablesubview.hpp" #include "tablesubview.hpp"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QEvent>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../filter/filterbox.hpp" #include "../filter/filterbox.hpp"
#include "table.hpp" #include "table.hpp"
@ -22,7 +24,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0); new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
layout->insertWidget (0, mTable = layout->insertWidget (0, mTable =
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting), 2); new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting, document), 2);
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
@ -43,6 +45,9 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
mTable->tableSizeUpdate(); mTable->tableSizeUpdate();
mTable->selectionSizeUpdate(); mTable->selectionSizeUpdate();
mTable->viewport()->installEventFilter(this);
mBottom->installEventFilter(this);
filterBox->installEventFilter(this);
if (mBottom->canCreateAndDelete()) if (mBottom->canCreateAndDelete())
{ {
@ -60,6 +65,14 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
connect (filterBox, connect (filterBox,
SIGNAL (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>)), SIGNAL (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>)),
mTable, SLOT (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>))); mTable, SLOT (recordFilterChanged (boost::shared_ptr<CSMFilter::Node>)));
connect(filterBox, SIGNAL(recordDropped(std::vector<CSMWorld::UniversalId>&, Qt::DropAction)),
this, SLOT(createFilterRequest(std::vector<CSMWorld::UniversalId>&, Qt::DropAction)));
connect(this, SIGNAL(useFilterRequest(const std::string&)), filterBox, SIGNAL(useFilterRequest(const std::string&)));
connect(this, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)),
filterBox, SIGNAL(createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >&, Qt::DropAction)));
} }
void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::setEditLock (bool locked)
@ -87,3 +100,33 @@ void CSVWorld::TableSubView::cloneRequest(const CSMWorld::UniversalId& toClone)
{ {
emit cloneRequest(toClone.getId(), toClone.getType()); emit cloneRequest(toClone.getId(), toClone.getType());
} }
void CSVWorld::TableSubView::createFilterRequest (std::vector< CSMWorld::UniversalId>& types, Qt::DropAction action)
{
std::vector<std::pair<std::string, std::vector<std::string> > > filterSource;
for (std::vector<CSMWorld::UniversalId>::iterator it = types.begin(); it != types.end(); ++it)
{
std::pair<std::string, std::vector<std::string> > pair( //splited long line
std::make_pair(it->getId(), mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(it->getType()))));
filterSource.push_back(pair);
}
emit createFilterRequest(filterSource, action);
}
bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event)
{
if (event->type() == QEvent::Drop)
{
QDropEvent* drop = dynamic_cast<QDropEvent*>(event);
const CSMWorld::TableMimeData* data = dynamic_cast<const CSMWorld::TableMimeData*>(drop->mimeData());
bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter);
if (handled)
{
emit useFilterRequest(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId());
}
return handled;
}
return false;
}

View file

@ -3,6 +3,8 @@
#include "../doc/subview.hpp" #include "../doc/subview.hpp"
#include <qt4/QtCore/qnamespace.h>
class QModelIndex; class QModelIndex;
namespace CSMWorld namespace CSMWorld
@ -39,14 +41,22 @@ namespace CSVWorld
virtual void setStatusBar (bool show); virtual void setStatusBar (bool show);
protected:
bool eventFilter(QObject* object, QEvent *event);
signals: signals:
void cloneRequest(const std::string&, void cloneRequest(const std::string&,
const CSMWorld::UniversalId::Type); const CSMWorld::UniversalId::Type);
void createFilterRequest(std::vector<std::pair<std::string, std::vector<std::string> > >& filterSource,
Qt::DropAction action);
void useFilterRequest(const std::string& idOfFilter);
private slots: private slots:
void editRequest (int row); void editRequest (int row);
void cloneRequest (const CSMWorld::UniversalId& toClone); void cloneRequest (const CSMWorld::UniversalId& toClone);
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
Qt::DropAction action);
}; };
} }

View file

@ -155,6 +155,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mSkipMenu (false) , mSkipMenu (false)
, mUseSound (true) , mUseSound (true)
, mCompileAll (false) , mCompileAll (false)
, mWarningsMode (1)
, mScriptContext (0) , mScriptContext (0)
, mFSStrict (false) , mFSStrict (false)
, mScriptConsoleMode (false) , mScriptConsoleMode (false)
@ -424,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mScriptContext->setExtensions (&mExtensions); mScriptContext->setExtensions (&mExtensions);
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
mVerboseScripts, *mScriptContext)); mVerboseScripts, *mScriptContext, mWarningsMode));
// Create game mechanics system // Create game mechanics system
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager; MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
@ -612,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path)
mStartupScript = path; mStartupScript = path;
} }
void OMW::Engine::setActivationDistanceOverride (int distance) void OMW::Engine::setActivationDistanceOverride (int distance)
{ {
mActivationDistanceOverride = distance; mActivationDistanceOverride = distance;
} }
void OMW::Engine::setWarningsMode (int mode)
{
mWarningsMode = mode;
}

View file

@ -74,6 +74,7 @@ namespace OMW
bool mSkipMenu; bool mSkipMenu;
bool mUseSound; bool mUseSound;
bool mCompileAll; bool mCompileAll;
int mWarningsMode;
std::string mFocusName; std::string mFocusName;
std::map<std::string,std::string> mFallbackMap; std::map<std::string,std::string> mFallbackMap;
bool mScriptConsoleMode; bool mScriptConsoleMode;
@ -181,6 +182,8 @@ namespace OMW
/// Override the game setting specified activation distance. /// Override the game setting specified activation distance.
void setActivationDistanceOverride (int distance); void setActivationDistanceOverride (int distance);
void setWarningsMode (int mode);
private: private:
Files::ConfigurationManager& mCfgMgr; Files::ConfigurationManager& mCfgMgr;
}; };

View file

@ -136,6 +136,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("script-run", bpo::value<std::string>()->default_value(""), ("script-run", bpo::value<std::string>()->default_value(""),
"select a file containing a list of console commands that is executed on startup") "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) ("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup") ->default_value(false), "skip main menu on game startup")
@ -241,6 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setScriptConsoleMode (variables["script-console"].as<bool>()); engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<std::string>()); engine.setStartupScript (variables["script-run"].as<std::string>());
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>()); engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
engine.setWarningsMode (variables["script-warn"].as<int>());
return true; return true;
} }

View file

@ -3,6 +3,14 @@
#include <string> #include <string>
#include <libs/platform/stdint.h>
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWWorld namespace MWWorld
{ {
class Ptr; class Ptr;
@ -52,6 +60,12 @@ namespace MWBase
virtual void persuade (int type) = 0; virtual void persuade (int type) = 0;
virtual int getTemporaryDispositionChange () const = 0; virtual int getTemporaryDispositionChange () const = 0;
virtual void applyDispositionChange (int delta) = 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;
}; };
} }

View file

@ -766,8 +766,11 @@ namespace MWClass
ensureCustomData (ptr); ensureCustomData (ptr);
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore-> CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
readState (state2.mInventory);
customData.mContainerStore->readState (state2.mInventory);
customData.mCreatureStats.readState (state2.mCreatureStats);
} }
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
@ -777,8 +780,10 @@ namespace MWClass
ensureCustomData (ptr); ensureCustomData (ptr);
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore-> CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
writeState (state2.mInventory);
customData.mContainerStore->writeState (state2.mInventory);
customData.mCreatureStats.writeState (state2.mCreatureStats);
} }
const ESM::GameSetting* Creature::fMinWalkSpeedCreature; const ESM::GameSetting* Creature::fMinWalkSpeedCreature;

View file

@ -1278,8 +1278,11 @@ namespace MWClass
ensureCustomData (ptr); ensureCustomData (ptr);
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore. CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
readState (state2.mInventory);
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) void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
@ -1289,8 +1292,11 @@ namespace MWClass
ensureCustomData (ptr); ensureCustomData (ptr);
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore. CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
writeState (state2.mInventory);
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; const ESM::GameSetting *Npc::fMinWalkSpeed;

View file

@ -8,6 +8,7 @@
#include <components/esm/loaddial.hpp> #include <components/esm/loaddial.hpp>
#include <components/esm/loadinfo.hpp> #include <components/esm/loadinfo.hpp>
#include <components/esm/dialoguestate.hpp>
#include <components/compiler/exception.hpp> #include <components/compiler/exception.hpp>
#include <components/compiler/errorhandler.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) std::vector<HyperTextToken> ParseHyperText(const std::string& text)
{ {

View file

@ -78,6 +78,12 @@ namespace MWDialogue
virtual void persuade (int type); virtual void persuade (int type);
virtual int getTemporaryDispositionChange () const; virtual int getTemporaryDispositionChange () const;
virtual void applyDispositionChange (int delta); 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);
}; };

View file

@ -206,9 +206,9 @@ struct JournalViewModelImpl : JournalViewModel
const MWDialogue::Quest& quest = i->second; const MWDialogue::Quest& quest = i->second;
// Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal. // Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal.
if (quest.getName().empty()) // Note that even with Tribunal, some quests still don't have quest names. I'm assuming those are not supposed
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first)); // to appear in the quest book.
else if (!quest.getName().empty())
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName())); visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
} }
} }

View file

@ -17,6 +17,7 @@
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
@ -451,7 +452,7 @@ namespace MWInput
mInputBinder->adjustMouseRegion(width, height); mInputBinder->adjustMouseRegion(width, height);
} }
bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
{ {
// Cut, copy & paste // Cut, copy & paste
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
@ -497,7 +498,6 @@ namespace MWInput
if (kc != OIS::KC_UNASSIGNED) if (kc != OIS::KC_UNASSIGNED)
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
return true;
} }
void InputManager::textInput(const SDL_TextInputEvent &arg) void InputManager::textInput(const SDL_TextInputEvent &arg)
@ -508,23 +508,21 @@ namespace MWInput
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
} }
bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) void InputManager::keyReleased(const SDL_KeyboardEvent &arg )
{ {
mInputBinder->keyReleased (arg); mInputBinder->keyReleased (arg);
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc));
return true;
} }
bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id )
{ {
mInputBinder->mousePressed (arg, id); mInputBinder->mousePressed (arg, id);
if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT) if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT)
return true; // MyGUI has no use for these events return; // MyGUI has no use for these events
MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id));
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
@ -535,20 +533,16 @@ namespace MWInput
MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f);
} }
} }
return true;
} }
bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id )
{ {
mInputBinder->mouseReleased (arg, id); mInputBinder->mouseReleased (arg, id);
MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id));
return true;
} }
bool InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg )
{ {
mInputBinder->mouseMoved (arg); mInputBinder->mouseMoved (arg);
@ -596,8 +590,6 @@ namespace MWInput
MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true);
} }
} }
return true;
} }
void InputManager::windowFocusChange(bool have_focus) void InputManager::windowFocusChange(bool have_focus)
@ -647,7 +639,9 @@ namespace MWInput
return; return;
// Not allowed if no spell selected // 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; return;
MWMechanics::DrawState_ state = mPlayer->getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();

View file

@ -86,13 +86,13 @@ namespace MWInput
virtual void resetToDefaultBindings(); virtual void resetToDefaultBindings();
public: public:
virtual bool keyPressed(const SDL_KeyboardEvent &arg ); virtual void keyPressed(const SDL_KeyboardEvent &arg );
virtual bool keyReleased( const SDL_KeyboardEvent &arg ); virtual void keyReleased( const SDL_KeyboardEvent &arg );
virtual void textInput (const SDL_TextInputEvent &arg); virtual void textInput (const SDL_TextInputEvent &arg);
virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual bool mouseMoved( const SFO::MouseMotionEvent &arg ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg );
virtual void windowVisibilityChange( bool visible ); virtual void windowVisibilityChange( bool visible );
virtual void windowFocusChange( bool have_focus ); virtual void windowFocusChange( bool have_focus );

View file

@ -13,7 +13,7 @@
#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/dialoguemanager.hpp"
#include "npcstats.hpp" #include "creaturestats.hpp"
#include "steering.hpp" #include "steering.hpp"
#include "movement.hpp" #include "movement.hpp"
#include "character.hpp" // fixme: for getActiveWeapon #include "character.hpp" // fixme: for getActiveWeapon
@ -138,11 +138,11 @@ namespace MWMechanics
{ {
MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState(); MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState();
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
actor.getClass().getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon); actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
//Get weapon speed and range //Get weapon speed and range
MWWorld::ContainerStoreIterator weaponSlot = MWWorld::ContainerStoreIterator weaponSlot =
MWMechanics::getActiveWeapon(cls.getNpcStats(actor), cls.getInventoryStore(actor), &weaptype); MWMechanics::getActiveWeapon(cls.getCreatureStats(actor), cls.getInventoryStore(actor), &weaptype);
if (weaptype == WeapType_HandToHand) if (weaptype == WeapType_HandToHand)
{ {
const MWWorld::Store<ESM::GameSetting> &gmst = const MWWorld::Store<ESM::GameSetting> &gmst =
@ -240,16 +240,20 @@ namespace MWMechanics
//target is at far distance: build path to target OR follow target (if previously actor had reached it once) //target is at far distance: build path to target OR follow target (if previously actor had reached it once)
mFollowTarget = false; mFollowTarget = false;
buildNewPath(actor); buildNewPath(actor); //not guaranteed, check before use
//delete visited path node //delete visited path node
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
//try shortcut //if buildNewPath() failed leave mTargetAngle unchanged
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget)) if(!mPathFinder.getPath().empty())
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees(); {
else //try shortcut
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
else
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
}
mRotate = true; mRotate = true;
mMovement.mPosition[1] = 1; mMovement.mPosition[1] = 1;
@ -300,9 +304,13 @@ namespace MWMechanics
dest.mZ = mTarget.getRefData().getPosition().pos[2]; dest.mZ = mTarget.getRefData().getPosition().pos[2];
Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ); Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ);
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); float dist = -1; //hack to indicate first time, to construct a new path
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ); if(!mPathFinder.getPath().empty())
float dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length()); {
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
}
float targetPosThreshold; float targetPosThreshold;
bool isOutside = actor.getCell()->mCell->isExterior(); bool isOutside = actor.getCell()->mCell->isExterior();
@ -311,7 +319,7 @@ namespace MWMechanics
else else
targetPosThreshold = 100; targetPosThreshold = 100;
if(dist > targetPosThreshold) if((dist < 0) || (dist > targetPosThreshold))
{ {
//construct new path only if target has moved away more than on <targetPosThreshold> //construct new path only if target has moved away more than on <targetPosThreshold>
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
@ -332,8 +340,11 @@ namespace MWMechanics
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path, //maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
//not the actual path length. Here we should know if the new path is actually more effective. //not the actual path length. Here we should know if the new path is actually more effective.
//if(pathFinder2.getPathSize() < mPathFinder.getPathSize()) //if(pathFinder2.getPathSize() < mPathFinder.getPathSize())
newPathFinder.syncStart(mPathFinder.getPath()); if(!mPathFinder.getPath().empty())
mPathFinder = newPathFinder; {
newPathFinder.syncStart(mPathFinder.getPath());
mPathFinder = newPathFinder;
}
} }
} }
} }

View file

@ -2,6 +2,8 @@
#include <algorithm> #include <algorithm>
#include <components/esm/creaturestats.hpp>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -457,4 +459,21 @@ namespace MWMechanics
mAttackStrength = value; 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]);
}
} }

View file

@ -12,6 +12,11 @@
#include "aisequence.hpp" #include "aisequence.hpp"
#include "drawstate.hpp" #include "drawstate.hpp"
namespace ESM
{
struct CreatureStats;
}
namespace MWMechanics namespace MWMechanics
{ {
/// \brief Common creature stats /// \brief Common creature stats
@ -212,6 +217,10 @@ namespace MWMechanics
std::set<int> mBoundItems; std::set<int> mBoundItems;
// Same as above // Same as above
std::map<int, std::string> mSummonedCreatures; std::map<int, std::string> mSummonedCreatures;
void writeState (ESM::CreatureStats& state) const;
void readState (const ESM::CreatureStats& state);
}; };
} }

View file

@ -12,6 +12,7 @@
#include <components/esm/loadclas.hpp> #include <components/esm/loadclas.hpp>
#include <components/esm/loadgmst.hpp> #include <components/esm/loadgmst.hpp>
#include <components/esm/loadfact.hpp> #include <components/esm/loadfact.hpp>
#include <components/esm/npcstats.hpp>
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -423,3 +424,89 @@ void MWMechanics::NpcStats::setTimeToStartDrowning(float time)
assert(time>=0 && time<=20); assert(time>=0 && time<=20);
mTimeToStartDrowning=time; 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;
}

View file

@ -13,6 +13,7 @@
namespace ESM namespace ESM
{ {
struct Class; struct Class;
struct NpcStats;
} }
namespace MWMechanics namespace MWMechanics
@ -128,6 +129,10 @@ namespace MWMechanics
/// Sets time left for the creature to drown if it stays underwater. /// Sets time left for the creature to drown if it stays underwater.
/// @param time value from [0,20] /// @param time value from [0,20]
void setTimeToStartDrowning(float time); void setTimeToStartDrowning(float time);
void writeState (ESM::NpcStats& state) const;
void readState (const ESM::NpcStats& state);
}; };
} }

View file

@ -391,6 +391,8 @@ namespace MWMechanics
void PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path) void PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path)
{ {
if (path.size() < 2)
return; //nothing to pop
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin(); std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin();
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin(); std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();

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

View file

@ -6,6 +6,8 @@
#include <limits> #include <limits>
#include <components/esm/statstate.hpp>
namespace MWMechanics namespace MWMechanics
{ {
template<typename T> template<typename T>
@ -86,6 +88,18 @@ namespace MWMechanics
{ {
mModified = mBase + modifier; 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> template<typename T>
@ -190,6 +204,18 @@ namespace MWMechanics
mStatic.setModifier (modifier); mStatic.setModifier (modifier);
setCurrent (getCurrent()+diff); 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> template<typename T>
@ -225,6 +251,10 @@ namespace MWMechanics
void damage(int damage) { mDamage += damage; } void damage(int damage) { mDamage += damage; }
void restore(int amount) { mDamage -= std::min(mDamage, amount); } void restore(int amount) { mDamage -= std::min(mDamage, amount); }
int getDamage() const { return mDamage; } int getDamage() const { return mDamage; }
void writeState (ESM::StatState<int>& state) const;
void readState (const ESM::StatState<int>& state);
}; };
class SkillValue : public AttributeValue class SkillValue : public AttributeValue
@ -234,6 +264,10 @@ namespace MWMechanics
SkillValue() : mProgress(0) {} SkillValue() : mProgress(0) {}
float getProgress() const { return mProgress; } float getProgress() const { return mProgress; }
void setProgress(float progress) { mProgress = progress; } 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) inline bool operator== (const AttributeValue& left, const AttributeValue& right)

View file

@ -285,6 +285,17 @@ void Animation::addAnimSource(const std::string &model)
} }
} }
if (grp == 0 && dstval->getNode()->getName() == "Bip01")
{
mNonAccumRoot = dstval->getNode();
mAccumRoot = mNonAccumRoot->getParent();
if(!mAccumRoot)
{
std::cerr<< "Non-Accum root for "<<mPtr.getCellRef().mRefID<<" is skeleton root??" <<std::endl;
mNonAccumRoot = NULL;
}
}
ctrls[i].setSource(mAnimationTimePtr[grp]); ctrls[i].setSource(mAnimationTimePtr[grp]);
grpctrls[grp].push_back(ctrls[i]); grpctrls[grp].push_back(ctrls[i]);
} }

View file

@ -16,9 +16,9 @@
namespace MWRender namespace MWRender
{ {
Ogre::AxisAlignedBox TerrainStorage::getBounds() void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY)
{ {
int minX = 0, minY = 0, maxX = 0, maxY = 0; minX = 0, minY = 0, maxX = 0, maxY = 0;
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
@ -39,8 +39,6 @@ namespace MWRender
// since grid coords are at cell origin, we need to add 1 cell // since grid coords are at cell origin, we need to add 1 cell
maxX += 1; maxX += 1;
maxY += 1; maxY += 1;
return Ogre::AxisAlignedBox(minX, minY, 0, maxX, maxY, 0);
} }
ESM::Land* TerrainStorage::getLand(int cellX, int cellY) ESM::Land* TerrainStorage::getLand(int cellX, int cellY)

View file

@ -1,6 +1,9 @@
#ifndef MWRENDER_TERRAINSTORAGE_H #ifndef MWRENDER_TERRAINSTORAGE_H
#define MWRENDER_TERRAINSTORAGE_H #define MWRENDER_TERRAINSTORAGE_H
#include <components/esm/loadland.hpp>
#include <components/esm/loadltex.hpp>
#include <components/terrain/storage.hpp> #include <components/terrain/storage.hpp>
namespace MWRender namespace MWRender
@ -14,7 +17,7 @@ namespace MWRender
public: public:
/// Get bounds of the whole terrain in cell units /// Get bounds of the whole terrain in cell units
virtual Ogre::AxisAlignedBox getBounds(); virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
/// Get the minimum and maximum heights of a terrain chunk. /// 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. /// @note Should only be called for chunks <= 1 cell, i.e. leafs of the quad tree.

View file

@ -3,6 +3,8 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include <components/esm/loaddial.hpp>
#include <components/compiler/locals.hpp> #include <components/compiler/locals.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -28,16 +30,32 @@ namespace MWScript
return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); 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()) script = MWWorld::Class::get (ptr).getScript (ptr);
return ' '; 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 bool CompilerContext::isId (const std::string& name) const
@ -67,4 +85,14 @@ namespace MWScript
store.get<ESM::Static>().search (name) || store.get<ESM::Static>().search (name) ||
store.get<ESM::Weapon>().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;
}
} }

View file

@ -30,11 +30,18 @@ namespace MWScript
/// 'l: long, 's': short, 'f': float, ' ': does not exist. /// 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getGlobalType (const std::string& name) const; virtual char getGlobalType (const std::string& name) const;
virtual char getMemberType (const std::string& name, const std::string& id) const; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. 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; virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced? ///< 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?
}; };
} }

View file

@ -52,7 +52,9 @@ op 0x20023: AiFollow, explicit reference
op 0x20024: AiFollowCell op 0x20024: AiFollowCell
op 0x20025: AiFollowCell, explicit reference op 0x20025: AiFollowCell, explicit reference
op 0x20026: ModRegion op 0x20026: ModRegion
opcodes 0x20027-0x3ffff unused op 0x20027: RemoveSoulGem
op 0x20028: RemoveSoulGem, explicit reference
opcodes 0x20029-0x3ffff unused
Segment 4: Segment 4:
(not implemented yet) (not implemented yet)
@ -308,8 +310,8 @@ op 0x20001f1: GetDetected
op 0x20001f2: GetDetected, explicit reference op 0x20001f2: GetDetected, explicit reference
op 0x20001f3: AddSoulGem op 0x20001f3: AddSoulGem
op 0x20001f4: AddSoulGem, explicit reference op 0x20001f4: AddSoulGem, explicit reference
op 0x20001f5: RemoveSoulGem op 0x20001f5: unused
op 0x20001f6: RemoveSoulGem, explicit reference op 0x20001f6: unused
op 0x20001f7: PlayBink op 0x20001f7: PlayBink
op 0x20001f8: Drop op 0x20001f8: Drop
op 0x20001f9: Drop, explicit reference op 0x20001f9: Drop, explicit reference
@ -381,5 +383,7 @@ op 0x200023a: StartCombat
op 0x200023b: StartCombatExplicit op 0x200023b: StartCombatExplicit
op 0x200023c: StopCombat op 0x200023c: StopCombat
op 0x200023d: StopCombatExplicit op 0x200023d: StopCombatExplicit
op 0x200023e: GetPcInJail
op 0x200023f: GetPcTraveling
opcodes 0x200023e-0x3ffffff unused opcodes 0x2000240-0x3ffffff unused

View file

@ -148,4 +148,25 @@ namespace MWScript
return false; 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;
}
} }

View file

@ -52,6 +52,10 @@ namespace MWScript
///< Records for variables that do not exist are dropped silently. ///< Records for variables that do not exist are dropped silently.
/// ///
/// \return Known type? /// \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.
}; };
} }

View file

@ -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 ( InterpreterContext::InterpreterContext (
MWScript::Locals *locals, MWWorld::Ptr reference) MWScript::Locals *locals, MWWorld::Ptr reference)
: mLocals (locals), mReference (reference), : mLocals (locals), mReference (reference),
@ -407,82 +448,80 @@ namespace MWScript
MWBase::Environment::get().getWorld()->disable (ref); 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 ( return locals.mShorts[index];
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().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 ( return locals.mLongs[index];
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().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 ( return locals.mFloats[index];
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
return ptr.getRefData().getLocals().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 ( locals.mShorts[index] = value;
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().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 ( locals.mLongs[index] = value;
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().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 ( locals.mFloats[index] = value;
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
ptr.getRefData().getLocals().mFloats[index] = value;
} }
MWWorld::Ptr InterpreterContext::getReference(bool required) MWWorld::Ptr InterpreterContext::getReference(bool required)

View file

@ -37,6 +37,12 @@ namespace MWScript
const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const; 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: public:
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference); InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference);
@ -138,17 +144,17 @@ namespace MWScript
virtual void disable (const std::string& id = ""); 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); MWWorld::Ptr getReference(bool required=true);
///< Reference, that the script is running from (can be empty) ///< Reference, that the script is running from (can be empty)

View file

@ -365,17 +365,21 @@ namespace MWScript
}; };
template<class R> template<class R>
class OpRemoveSoulGem : public Interpreter::Opcode0 class OpRemoveSoulGem : public Interpreter::Opcode1
{ {
public: public:
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
std::string soul = runtime.getStringLiteral (runtime[0].mInteger); std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); 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); MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) 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) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); 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::opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>); interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>); interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>); 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::opcodeCastExplicit, new OpCast<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling);
} }
} }
} }

View file

@ -7,22 +7,28 @@
#include <exception> #include <exception>
#include <components/esm/loadscpt.hpp> #include <components/esm/loadscpt.hpp>
#include "../mwworld/esmstore.hpp"
#include <components/misc/stringops.hpp>
#include <components/compiler/scanner.hpp> #include <components/compiler/scanner.hpp>
#include <components/compiler/context.hpp> #include <components/compiler/context.hpp>
#include <components/compiler/exception.hpp> #include <components/compiler/exception.hpp>
#include <components/compiler/quickfileparser.hpp>
#include "../mwworld/esmstore.hpp"
#include "extensions.hpp" #include "extensions.hpp"
namespace MWScript namespace MWScript
{ {
ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose, ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose,
Compiler::Context& compilerContext) Compiler::Context& compilerContext, int warningsMode)
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
mOpcodesInstalled (false), mGlobalScripts (store) mOpcodesInstalled (false), mGlobalScripts (store)
{} {
mErrorHandler.setWarningsMode (warningsMode);
}
bool ScriptManager::compile (const std::string& name) bool ScriptManager::compile (const std::string& name)
{ {
@ -138,37 +144,33 @@ namespace MWScript
Compiler::Locals& ScriptManager::getLocals (const std::string& name) 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()) if (iter!=mScripts.end())
return iter->second.second; 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()) if (iter!=mOtherLocals.end())
return iter->second; return iter->second;
} }
Compiler::Locals locals; if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2))
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
{ {
int index = 0; Compiler::Locals locals;
for (int i=0; i<script->mData.mNumShorts; ++i) std::istringstream stream (script->mScriptText);
locals.declare ('s', script->mVarNames[index++]); Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals);
Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions());
for (int i=0; i<script->mData.mNumLongs; ++i) scanner.scan (parser);
locals.declare ('l', script->mVarNames[index++]);
for (int i=0; i<script->mData.mNumFloats; ++i)
locals.declare ('f', script->mVarNames[index++]);
std::map<std::string, Compiler::Locals>::iterator iter = 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; return iter->second;
} }
@ -214,8 +216,10 @@ namespace MWScript
throw std::runtime_error ("invalid variable type"); throw std::runtime_error ("invalid variable type");
} }
std::string variable2 = Misc::StringUtils::lowerCase (variable);
for (int i=0; i<size; ++i) 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; return i;
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);

View file

@ -52,7 +52,7 @@ namespace MWScript
public: public:
ScriptManager (const MWWorld::ESMStore& store, bool verbose, 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); virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
///< Run the script with the given name (compile first, if not compiled yet) ///< Run the script with the given name (compile first, if not compiled yet)

View file

@ -172,6 +172,7 @@ class OpenAL_SoundStream : public Sound
DecoderPtr mDecoder; DecoderPtr mDecoder;
volatile bool mIsFinished; volatile bool mIsFinished;
volatile bool mIsInitialBatchEnqueued;
void updateAll(bool local); void updateAll(bool local);
@ -264,7 +265,7 @@ private:
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags)
: Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)
, mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true) , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false)
{ {
throwALerror(); throwALerror();
@ -315,16 +316,8 @@ void OpenAL_SoundStream::play()
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
throwALerror(); throwALerror();
mSamplesQueued = 0; mSamplesQueued = 0;
for(ALuint i = 0;i < sNumBuffers;i++)
alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate);
throwALerror();
alSourceQueueBuffers(mSource, sNumBuffers, mBuffers);
alSourcePlay(mSource);
throwALerror();
mIsFinished = false; mIsFinished = false;
mIsInitialBatchEnqueued = false;
mOutput.mStreamThread->add(this); mOutput.mStreamThread->add(this);
} }
@ -332,6 +325,7 @@ void OpenAL_SoundStream::stop()
{ {
mOutput.mStreamThread->remove(this); mOutput.mStreamThread->remove(this);
mIsFinished = true; mIsFinished = true;
mIsInitialBatchEnqueued = false;
alSourceStop(mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
@ -444,6 +438,24 @@ bool OpenAL_SoundStream::process()
} while(processed > 0); } while(processed > 0);
throwALerror(); throwALerror();
} }
else if (!mIsInitialBatchEnqueued) { // nothing enqueued yet
std::vector<char> data(mBufferSize);
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);
}
}
mIsInitialBatchEnqueued = true;
}
if(state != AL_PLAYING && state != AL_PAUSED) if(state != AL_PLAYING && state != AL_PAUSED)
{ {
@ -461,6 +473,7 @@ bool OpenAL_SoundStream::process()
std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl; std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl;
mSamplesQueued = 0; mSamplesQueued = 0;
mIsFinished = true; mIsFinished = true;
mIsInitialBatchEnqueued = false;
} }
return !mIsFinished; return !mIsFinished;
} }

View file

@ -176,7 +176,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
else else
slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile);
std::ofstream stream (slot->mPath.string().c_str()); std::ofstream stream (slot->mPath.string().c_str(), std::ios::binary);
ESM::ESMWriter writer; ESM::ESMWriter writer;
@ -193,7 +193,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getJournal()->countSavedGameRecords() +MWBase::Environment::get().getJournal()->countSavedGameRecords()
+MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords()
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+ 1 // global map +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
+1 // global map
); );
writer.save (stream); writer.save (stream);
@ -203,6 +204,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
writer.endRecord (ESM::REC_SAVE); writer.endRecord (ESM::REC_SAVE);
MWBase::Environment::get().getJournal()->write (writer); MWBase::Environment::get().getJournal()->write (writer);
MWBase::Environment::get().getDialogueManager()->write (writer);
MWBase::Environment::get().getWorld()->write (writer); MWBase::Environment::get().getWorld()->write (writer);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer); MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
MWBase::Environment::get().getWindowManager()->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); MWBase::Environment::get().getJournal()->readRecord (reader, n.val);
break; break;
case ESM::REC_DIAS:
MWBase::Environment::get().getDialogueManager()->readRecord (reader, n.val);
break;
case ESM::REC_ALCH: case ESM::REC_ALCH:
case ESM::REC_ARMO: case ESM::REC_ARMO:
case ESM::REC_BOOK: case ESM::REC_BOOK:

View file

@ -529,12 +529,6 @@ namespace MWWorld
return mPlayer->getPlayer(); 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); std::string lowerCaseName = Misc::StringUtils::lowerCase(name);
// active cells // active cells
@ -548,6 +542,12 @@ namespace MWWorld
return ptr; return ptr;
} }
Ptr ptr = Class::get (mPlayer->getPlayer()).
getContainerStore (mPlayer->getPlayer()).search (lowerCaseName);
if (!ptr.isEmpty())
return ptr;
if (!activeOnly) if (!activeOnly)
{ {
ret = mCells.getPtr (lowerCaseName); ret = mCells.getPtr (lowerCaseName);
@ -610,6 +610,10 @@ namespace MWWorld
void World::enable (const Ptr& reference) void World::enable (const Ptr& reference)
{ {
// enable is a no-op for items in containers
if (!reference.isInCell())
return;
if (!reference.getRefData().isEnabled()) if (!reference.getRefData().isEnabled())
{ {
reference.getRefData().enable(); reference.getRefData().enable();
@ -640,6 +644,10 @@ namespace MWWorld
void World::disable (const Ptr& reference) void World::disable (const Ptr& reference)
{ {
// disable is a no-op for items in containers
if (!reference.isInCell())
return;
if (reference.getRefData().isEnabled()) if (reference.getRefData().isEnabled())
{ {
reference.getRefData().disable(); reference.getRefData().disable();

View file

@ -1,177 +0,0 @@
# Locate SDL library
# This module defines
# SDL_LIBRARY, the name of the library to link against
# SDL_FOUND, if false, do not try to link to SDL
# SDL_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL_BUILDING_LIBRARY
# If this is defined, then no SDL_main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL_LIBRARY variable.
#
# Don't forget to include SDLmain.h and SDLmain.m your project for the
# OS X framework based version. (Other versions link to -lSDLmain which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL_LIBRARY_TEMP in your configuration
# and no SDL_LIBRARY, it means CMake did not find your SDL library
# (SDL.dll, libsdl.so, SDL.framework, etc).
# Set SDL_LIBRARY_TEMP to point to your SDL library, and configure again.
# Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL_LIBRARY
# variable, but when these values are unset, SDL_LIBRARY does not get created.
#
#
# $SDLDIR is an environment variable that would
# correspond to the ./configure --prefix=$SDLDIR
# used in building SDL.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL guidelines.
# Added a search for SDLmain which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL/SDL.h to just SDL.h
# This needed to change because "proper" SDL convention
# is #include "SDL.h", not <SDL/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL/ (see FreeBSD).
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
FIND_PATH(SDL_INCLUDE_DIR SDL.h
HINTS
$ENV{SDLDIR}
PATH_SUFFIXES include/SDL include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL12
/usr/local/include/SDL11 # FreeBSD ports
/usr/include/SDL12
/usr/include/SDL11
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
#MESSAGE("SDL_INCLUDE_DIR is ${SDL_INCLUDE_DIR}")
# SDL-1.1 is the name used by FreeBSD ports...
# don't confuse it for the version number.
FIND_LIBRARY(SDL_LIBRARY_TEMP
NAMES SDL SDL-1.1
HINTS
$ENV{SDLDIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
#MESSAGE("SDL_LIBRARY_TEMP is ${SDL_LIBRARY_TEMP}")
IF(NOT SDL_BUILDING_LIBRARY)
IF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDLmain for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDLMAIN_LIBRARY
NAMES SDLmain SDLmain-1.1
HINTS
$ENV{SDLDIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL_BUILDING_LIBRARY)
# SDL may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional library, mwindows
# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -lmwindows
# (Actually on second look, I think it only needs one of the m* libraries.)
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
SET(SDL_FOUND "NO")
IF(SDL_LIBRARY_TEMP)
# For SDLmain
IF(NOT SDL_BUILDING_LIBRARY)
IF(SDLMAIN_LIBRARY)
SET(SDL_LIBRARY_TEMP ${SDLMAIN_LIBRARY} ${SDL_LIBRARY_TEMP})
ENDIF(SDLMAIN_LIBRARY)
ENDIF(NOT SDL_BUILDING_LIBRARY)
# For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP})
ENDIF(MINGW)
# Set the final string here so the GUI reflects the final state.
SET(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL_LIBRARY_TEMP "${SDL_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL_FOUND "YES")
ENDIF(SDL_LIBRARY_TEMP)
#MESSAGE("SDL_LIBRARY is ${SDL_LIBRARY}")

View file

@ -85,10 +85,6 @@ function(get_git_head_revision _refspecvar _hashvar)
endfunction() endfunction()
function(git_describe _var) function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
#get_git_head_revision(refspec hash) #get_git_head_revision(refspec hash)
if(NOT GIT_FOUND) if(NOT GIT_FOUND)
@ -133,7 +129,8 @@ endfunction()
function(get_git_tag_revision _var) function(get_git_tag_revision _var)
if(NOT GIT_FOUND) if(NOT GIT_FOUND)
find_package(Git QUIET) set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif() endif()
execute_process(COMMAND execute_process(COMMAND

View file

@ -44,7 +44,8 @@ add_component_dir (esm
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter 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 add_component_dir (misc
@ -59,7 +60,8 @@ add_component_dir (files
add_component_dir (compiler add_component_dir (compiler
context controlparser errorhandler exception exprparser extensions fileparser generator context controlparser errorhandler exception exprparser extensions fileparser generator
lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler 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 add_component_dir (interpreter

View file

@ -33,11 +33,18 @@ namespace Compiler
virtual char getGlobalType (const std::string& name) const = 0; virtual char getGlobalType (const std::string& name) const = 0;
///< 'l: long, 's': short, 'f': float, ' ': does not exist. ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const = 0; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. 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; virtual bool isId (const std::string& name) const = 0;
///< Does \a name match an ID, that can be referenced? ///< 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?
}; };
} }

View file

@ -7,6 +7,8 @@
#include "scanner.hpp" #include "scanner.hpp"
#include "generator.hpp" #include "generator.hpp"
#include "errorhandler.hpp"
#include "skipparser.hpp"
namespace Compiler namespace Compiler
{ {
@ -70,7 +72,7 @@ namespace Compiler
} }
else if (keyword==Scanner::K_else) else if (keyword==Scanner::K_else)
{ {
mState = IfElseEndState; mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that
} }
return true; return true;
@ -106,7 +108,7 @@ namespace Compiler
Codes expr; Codes expr;
mExprParser.append (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)); std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
@ -120,7 +122,7 @@ namespace Compiler
Codes loop2; 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()) if (loop.size()!=loop2.size())
throw std::logic_error ( 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) Literals& literals)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
mLineParser (errorHandler, context, locals, literals, mCodeBlock), mLineParser (errorHandler, context, locals, literals, mCodeBlock),
@ -186,8 +188,11 @@ namespace Compiler
{ {
if (mState==StartState) 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(); mExprParser.reset();
scanner.scan (mExprParser); scanner.scan (mExprParser);
@ -203,7 +208,8 @@ namespace Compiler
return true; 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)) if (parseIfBody (keyword, loc, scanner))
return true; return true;
@ -226,6 +232,7 @@ namespace Compiler
case IfEndState: mState = IfBodyState; return true; case IfEndState: mState = IfBodyState; return true;
case IfElseifEndState: mState = IfElseifBodyState; return true; case IfElseifEndState: mState = IfElseifBodyState; return true;
case IfElseEndState: mState = IfElseBodyState; return true; case IfElseEndState: mState = IfElseBodyState; return true;
case IfElseJunkState: mState = IfElseBodyState; return true;
case WhileEndState: mState = WhileBodyState; return true; case WhileEndState: mState = WhileBodyState; return true;
@ -243,7 +250,13 @@ namespace Compiler
default: ; 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); return Parser::parseSpecial (code, loc, scanner);

View file

@ -26,7 +26,8 @@ namespace Compiler
IfElseEndState, IfElseBodyState, IfElseEndState, IfElseBodyState,
IfEndifState, IfEndifState,
WhileEndState, WhileBodyState, WhileEndState, WhileBodyState,
WhileEndwhileState WhileEndwhileState,
IfElseJunkState
}; };
typedef std::vector<Interpreter::Type_Code> Codes; typedef std::vector<Interpreter::Type_Code> Codes;
@ -47,7 +48,7 @@ namespace Compiler
public: public:
ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals); Literals& literals);
void appendCode (std::vector<Interpreter::Type_Code>& code) const; void appendCode (std::vector<Interpreter::Type_Code>& code) const;

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

View 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

View file

@ -5,7 +5,7 @@ namespace Compiler
{ {
// constructor // constructor
ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0) {} ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0), mWarningsMode (1) {}
// destructor // destructor
@ -36,8 +36,13 @@ namespace Compiler
void ErrorHandler::warning (const std::string& message, const TokenLoc& loc) void ErrorHandler::warning (const std::string& message, const TokenLoc& loc)
{ {
++mWarnings; if (mWarningsMode==1)
report (message, loc, WarningMessage); {
++mWarnings;
report (message, loc, WarningMessage);
}
else if (mWarningsMode==2)
error (message, loc);
} }
// Generate an error message. // Generate an error message.
@ -62,4 +67,9 @@ namespace Compiler
{ {
mErrors = mWarnings = 0; mErrors = mWarnings = 0;
} }
void ErrorHandler::setWarningsMode (int mode)
{
mWarningsMode = mode;
}
} }

View file

@ -16,6 +16,7 @@ namespace Compiler
{ {
int mWarnings; int mWarnings;
int mErrors; int mErrors;
int mWarningsMode;
protected: protected:
@ -60,8 +61,11 @@ namespace Compiler
void endOfFile(); void endOfFile();
///< Generate an error message for an unexpected EOF. ///< Generate an error message for an unexpected EOF.
virtual void reset(); virtual void reset();
///< Remove all previous error/warning events ///< Remove all previous error/warning events
void setWarningsMode (int mode);
///< // 0 ignore, 1 rate as warning, 2 rate as error
}; };
} }

View file

@ -7,6 +7,8 @@
#include <stack> #include <stack>
#include <iterator> #include <iterator>
#include <components/misc/stringops.hpp>
#include "generator.hpp" #include "generator.hpp"
#include "scanner.hpp" #include "scanner.hpp"
#include "errorhandler.hpp" #include "errorhandler.hpp"
@ -14,7 +16,6 @@
#include "stringparser.hpp" #include "stringparser.hpp"
#include "extensions.hpp" #include "extensions.hpp"
#include "context.hpp" #include "context.hpp"
#include <components/misc/stringops.hpp>
namespace Compiler namespace Compiler
{ {
@ -203,21 +204,22 @@ namespace Compiler
std::string name2 = Misc::StringUtils::lowerCase (name); std::string name2 = Misc::StringUtils::lowerCase (name);
std::string id = Misc::StringUtils::lowerCase (mExplicit); 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; mNextOperand = false;
mExplicit.clear(); mExplicit.clear();
mOperands.push_back (type=='f' ? 'f' : 'l'); mOperands.push_back (type.first=='f' ? 'f' : 'l');
return true; return true;
} }
return false; return false;
} }
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ExprParser::ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, bool argument) Literals& literals, bool argument)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false) mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false)
@ -308,6 +310,22 @@ namespace Compiler
return true; 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)) if (mExplicit.empty() && getContext().isId (name2))
{ {
mExplicit = name2; mExplicit = name2;
@ -326,6 +344,31 @@ namespace Compiler
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) 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; mFirst = false;
if (!mExplicit.empty()) if (!mExplicit.empty())
@ -368,8 +411,15 @@ namespace Compiler
char returnType; char returnType;
std::string argumentType; 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(); start();
mTokenLoc = loc; mTokenLoc = loc;
@ -490,7 +540,9 @@ namespace Compiler
char returnType; char returnType;
std::string argumentType; std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, false)) bool hasExplicit = false;
if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit))
{ {
mTokenLoc = loc; mTokenLoc = loc;
int optionals = parseArguments (argumentType, scanner); int optionals = parseArguments (argumentType, scanner);
@ -518,6 +570,14 @@ namespace Compiler
{ {
if (!mExplicit.empty()) 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) if (!mRefOp && code==Scanner::S_ref)
{ {
mRefOp = true; mRefOp = true;
@ -687,11 +747,11 @@ namespace Compiler
{ {
optional = true; optional = true;
} }
else if (*iter=='S' || *iter=='c') else if (*iter=='S' || *iter=='c' || *iter=='x')
{ {
stringParser.reset(); stringParser.reset();
if (optional) if (optional || *iter=='x')
stringParser.setOptional (true); stringParser.setOptional (true);
if (*iter=='c') stringParser.smashCase(); if (*iter=='c') stringParser.smashCase();
@ -700,18 +760,21 @@ namespace Compiler
if (optional && stringParser.isEmpty()) if (optional && stringParser.isEmpty())
break; break;
if (invert) if (*iter!='x')
{ {
std::vector<Interpreter::Type_Code> tmp; if (invert)
stringParser.append (tmp); {
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 else
{ {

View file

@ -58,7 +58,7 @@ namespace Compiler
public: public:
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, bool argument = false); Literals& literals, bool argument = false);
///< constructor ///< constructor
/// \param argument Parser is used to parse function- or instruction- /// \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, /// \param arguments Each character represents one arguments ('l': integer,
/// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
/// optional) /// optional)
/// 'x': optional string that will be ignored (die in a fire, MW script compiler!)
/// \param invert Store arguments in reverted order. /// \param invert Store arguments in reverted order.
/// \return number of optional arguments /// \return number of optional arguments
}; };

View file

@ -22,7 +22,7 @@ namespace Compiler
} }
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType, 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); std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
@ -30,7 +30,7 @@ namespace Compiler
return false; return false;
if (explicitReference && iter->second.mCodeExplicit==-1) if (explicitReference && iter->second.mCodeExplicit==-1)
return false; explicitReference = false;
returnType = iter->second.mReturn; returnType = iter->second.mReturn;
argumentType = iter->second.mArguments; argumentType = iter->second.mArguments;
@ -38,7 +38,7 @@ namespace Compiler
} }
bool Extensions::isInstruction (int keyword, std::string& argumentType, bool Extensions::isInstruction (int keyword, std::string& argumentType,
bool explicitReference) const bool& explicitReference) const
{ {
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword); std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
@ -46,7 +46,7 @@ namespace Compiler
return false; return false;
if (explicitReference && iter->second.mCodeExplicit==-1) if (explicitReference && iter->second.mCodeExplicit==-1)
return false; explicitReference = false;
argumentType = iter->second.mArguments; argumentType = iter->second.mArguments;
return true; return true;

View file

@ -47,13 +47,17 @@ namespace Compiler
/// - keyword must be all lower case. /// - keyword must be all lower case.
bool isFunction (int keyword, char& returnType, std::string& argumentType, 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 ///< Is this keyword registered with a function? If yes, return return and argument
/// types. /// 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 isInstruction (int keyword, std::string& argumentType,
bool explicitReference) const; bool& explicitReference) const;
///< Is this keyword registered with a function? If yes, return argument types. ///< 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, void registerFunction (const std::string& keyword, char returnType,
const std::string& argumentType, int code, int codeExplicit = -1); const std::string& argumentType, int code, int codeExplicit = -1);

View file

@ -41,7 +41,7 @@ namespace Compiler
opcodeAiEscortCellExplicit); opcodeAiEscortCellExplicit);
extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander,
opcodeAiWanderExplicit); opcodeAiWanderExplicit);
extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow, extensions.registerInstruction ("aifollow", "cffff/llllllll", opcodeAiFollow,
opcodeAiFollowExplicit); opcodeAiFollowExplicit);
extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell,
opcodeAiFollowCellExplicit); opcodeAiFollowCellExplicit);
@ -62,7 +62,7 @@ namespace Compiler
extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI);
extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI);
extensions.registerInstruction("startcombat", "c", opcodeStartCombat, opcodeStartCombatExplicit); 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 ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
@ -253,7 +253,7 @@ namespace Compiler
extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit);
extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit);
extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); 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 ("drop", "cl", opcodeDrop, opcodeDropExplicit);
extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit);
extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit);
@ -276,6 +276,8 @@ namespace Compiler
extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode);
extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation);
extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); 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 ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);
extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("addspell", "cx", opcodeAddSpell, opcodeAddSpellExplicit);
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
opcodeRemoveSpellExplicit); opcodeRemoveSpellExplicit);
extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects, extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects,

View file

@ -260,34 +260,34 @@ namespace
code.push_back (Compiler::Generator::segment5 (44)); 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) void opRandom (Compiler::Generator::CodeContainer& code)
@ -593,7 +593,7 @@ namespace Compiler
else if (offset<0) else if (offset<0)
opJumpBackward (code, -offset); opJumpBackward (code, -offset);
else else
throw std::logic_error ("inifite loop"); throw std::logic_error ("infinite loop");
} }
void jumpOnZero (CodeContainer& code, int offset) void jumpOnZero (CodeContainer& code, int offset)
@ -738,7 +738,8 @@ namespace Compiler
} }
void assignToMember (CodeContainer& code, Literals& literals, char localType, 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); int index = literals.addString (name);
@ -766,17 +767,17 @@ namespace Compiler
{ {
case 'f': case 'f':
opStoreMemberFloat (code); opStoreMemberFloat (code, global);
break; break;
case 's': case 's':
opStoreMemberShort (code); opStoreMemberShort (code, global);
break; break;
case 'l': case 'l':
opStoreMemberLong (code); opStoreMemberLong (code, global);
break; break;
default: default:
@ -786,7 +787,7 @@ namespace Compiler
} }
void fetchMember (CodeContainer& code, Literals& literals, char localType, 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); int index = literals.addString (name);
@ -800,17 +801,17 @@ namespace Compiler
{ {
case 'f': case 'f':
opFetchMemberFloat (code); opFetchMemberFloat (code, global);
break; break;
case 's': case 's':
opFetchMemberShort (code); opFetchMemberShort (code, global);
break; break;
case 'l': case 'l':
opFetchMemberLong (code); opFetchMemberLong (code, global);
break; break;
default: default:

View file

@ -102,10 +102,12 @@ namespace Compiler
const std::string& name); const std::string& name);
void assignToMember (CodeContainer& code, Literals& literals, char memberType, 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, 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); void random (CodeContainer& code);

View file

@ -1,6 +1,8 @@
#include "lineparser.hpp" #include "lineparser.hpp"
#include <components/misc/stringops.hpp>
#include "scanner.hpp" #include "scanner.hpp"
#include "context.hpp" #include "context.hpp"
#include "errorhandler.hpp" #include "errorhandler.hpp"
@ -8,7 +10,7 @@
#include "locals.hpp" #include "locals.hpp"
#include "generator.hpp" #include "generator.hpp"
#include "extensions.hpp" #include "extensions.hpp"
#include <components/misc/stringops.hpp> #include "declarationparser.hpp"
namespace Compiler 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) Literals& literals, std::vector<Interpreter::Type_Code>& code, bool allowExpression)
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code), : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code),
mState (BeginState), mExprParser (errorHandler, context, locals, literals), mState (BeginState), mExprParser (errorHandler, context, locals, literals),
@ -82,33 +84,9 @@ namespace Compiler
bool LineParser::parseName (const std::string& name, const TokenLoc& loc, bool LineParser::parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner) Scanner& scanner)
{ {
if (mState==ShortState || mState==LongState || mState==FloatState) if (mState==PotentialEndState)
{ {
if (!getContext().canDeclareLocals()) getErrorHandler().warning ("stay string argument (ignoring it)", loc);
{
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);
mState = EndState; mState = EndState;
return true; return true;
} }
@ -142,12 +120,13 @@ namespace Compiler
if (mState==SetMemberVarState) if (mState==SetMemberVarState)
{ {
mMemberName = name; mMemberName = name;
char type = getContext().getMemberType (mMemberName, mName); std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
if (type!=' ') if (type.first!=' ')
{ {
mState = SetMemberVarState2; mState = SetMemberVarState2;
mType = type; mType = type.first;
mReferenceMember = type.second;
return true; return true;
} }
@ -240,6 +219,34 @@ namespace Compiler
bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) 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) if (mState==BeginState || mState==ExplicitState)
{ {
switch (keyword) switch (keyword)
@ -247,13 +254,13 @@ namespace Compiler
case Scanner::K_enable: case Scanner::K_enable:
Generator::enable (mCode, mLiterals, mExplicit); Generator::enable (mCode, mLiterals, mExplicit);
mState = EndState; mState = PotentialEndState;
return true; return true;
case Scanner::K_disable: case Scanner::K_disable:
Generator::disable (mCode, mLiterals, mExplicit); Generator::disable (mCode, mLiterals, mExplicit);
mState = EndState; mState = PotentialEndState;
return true; return true;
} }
@ -262,8 +269,15 @@ namespace Compiler
{ {
std::string argumentType; 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); int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals); extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
@ -287,9 +301,16 @@ namespace Compiler
char returnType; char returnType;
std::string argumentType; std::string argumentType;
if (extensions->isFunction (keyword, returnType, argumentType, bool hasExplicit = !mExplicit.empty();
!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); scanner.putbackKeyword (keyword, loc);
parseExpression (scanner, loc); parseExpression (scanner, loc);
mState = EndState; 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) if (mState==BeginState)
{ {
switch (keyword) switch (keyword)
{ {
case Scanner::K_short: mState = ShortState; return true; case Scanner::K_short:
case Scanner::K_long: mState = LongState; return true; case Scanner::K_long:
case Scanner::K_float: mState = FloatState; return true; 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_set: mState = SetState; return true;
case Scanner::K_messagebox: mState = MessageState; return true; case Scanner::K_messagebox: mState = MessageState; return true;
@ -328,6 +374,24 @@ namespace Compiler
Generator::stopScript (mCode); Generator::stopScript (mCode);
mState = EndState; mState = EndState;
return true; 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) else if (mState==SetLocalVarState && keyword==Scanner::K_to)
@ -365,7 +429,8 @@ namespace Compiler
std::vector<Interpreter::Type_Code> code; std::vector<Interpreter::Type_Code> code;
char type = mExprParser.append (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; mState = EndState;
return true; return true;
@ -389,7 +454,8 @@ namespace Compiler
bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) 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; return false;
if (code==Scanner::S_comma && mState==MessageState) if (code==Scanner::S_comma && mState==MessageState)

View file

@ -20,11 +20,10 @@ namespace Compiler
enum State enum State
{ {
BeginState, BeginState,
ShortState, LongState, FloatState,
SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState,
SetMemberVarState, SetMemberVarState2, SetMemberVarState, SetMemberVarState2,
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
EndState, EndState, PotentialEndState /* may have a stray string argument */,
PotentialExplicitState, ExplicitState, MemberState PotentialExplicitState, ExplicitState, MemberState
}; };
@ -34,6 +33,7 @@ namespace Compiler
State mState; State mState;
std::string mName; std::string mName;
std::string mMemberName; std::string mMemberName;
bool mReferenceMember;
int mButtons; int mButtons;
std::string mExplicit; std::string mExplicit;
char mType; char mType;
@ -44,7 +44,7 @@ namespace Compiler
public: public:
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals,
Literals& literals, std::vector<Interpreter::Type_Code>& code, Literals& literals, std::vector<Interpreter::Type_Code>& code,
bool allowExpression = false); bool allowExpression = false);
///< \param allowExpression Allow lines consisting of a naked expression ///< \param allowExpression Allow lines consisting of a naked expression

View file

@ -7,6 +7,8 @@
#include <ostream> #include <ostream>
#include <iterator> #include <iterator>
#include <components/misc/stringops.hpp>
namespace Compiler namespace Compiler
{ {
const std::vector<std::string>& Locals::get (char type) const 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) 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() void Locals::clear()

View file

@ -203,8 +203,8 @@ namespace Compiler
const int opcodeGetEffectExplicit = 0x20001d0; const int opcodeGetEffectExplicit = 0x20001d0;
const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGem = 0x20001f3;
const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeAddSoulGemExplicit = 0x20001f4;
const int opcodeRemoveSoulGem = 0x20001f5; const int opcodeRemoveSoulGem = 0x20027;
const int opcodeRemoveSoulGemExplicit = 0x20001f6; const int opcodeRemoveSoulGemExplicit = 0x20028;
const int opcodeDrop = 0x20001f8; const int opcodeDrop = 0x20001f8;
const int opcodeDropExplicit = 0x20001f9; const int opcodeDropExplicit = 0x20001f9;
const int opcodeDropSoulGem = 0x20001fa; const int opcodeDropSoulGem = 0x20001fa;
@ -245,6 +245,8 @@ namespace Compiler
const int opcodeCastExplicit = 0x2000228; const int opcodeCastExplicit = 0x2000228;
const int opcodeExplodeSpell = 0x2000229; const int opcodeExplodeSpell = 0x2000229;
const int opcodeExplodeSpellExplicit = 0x200022a; const int opcodeExplodeSpellExplicit = 0x200022a;
const int opcodeGetPcInJail = 0x200023e;
const int opcodeGetPcTraveling = 0x200023f;
} }
namespace Sky namespace Sky

View file

@ -52,7 +52,7 @@ namespace Compiler
// Return context // Return context
Context& Parser::getContext() const Context& Parser::getContext() const
{ {
return mContext; return mContext;
} }
@ -64,7 +64,7 @@ namespace Compiler
return lowerCase; return lowerCase;
} }
Parser::Parser (ErrorHandler& errorHandler, Context& context) Parser::Parser (ErrorHandler& errorHandler, const Context& context)
: mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true) : mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
{} {}

View file

@ -17,7 +17,7 @@ namespace Compiler
class Parser class Parser
{ {
ErrorHandler& mErrorHandler; ErrorHandler& mErrorHandler;
Context& mContext; const Context& mContext;
bool mOptional; bool mOptional;
bool mEmpty; bool mEmpty;
@ -38,14 +38,14 @@ namespace Compiler
ErrorHandler& getErrorHandler(); ErrorHandler& getErrorHandler();
///< Return error handler ///< Return error handler
Context& getContext(); const Context& getContext() const;
///< Return context ///< Return context
static std::string toLower (const std::string& name); static std::string toLower (const std::string& name);
public: public:
Parser (ErrorHandler& errorHandler, Context& context); Parser (ErrorHandler& errorHandler, const Context& context);
///< constructor ///< constructor
virtual ~Parser(); virtual ~Parser();

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

View 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

View file

@ -370,9 +370,9 @@ namespace Compiler
if (c=='\n') if (c=='\n')
special = S_newline; special = S_newline;
else if (c=='(') else if (c=='(' || c=='[') /// \todo option to disable the use of [ as alias for (
special = S_open; special = S_open;
else if (c==')') else if (c==')' || c==']') /// \todo option to disable the use of ] as alias for )
special = S_close; special = S_close;
else if (c=='.') else if (c=='.')
{ {

View file

@ -7,7 +7,7 @@
namespace Compiler namespace Compiler
{ {
ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context, ScriptParser::ScriptParser (ErrorHandler& errorHandler, const Context& context,
Locals& locals, bool end) Locals& locals, bool end)
: Parser (errorHandler, context), mOutput (locals), : Parser (errorHandler, context), mOutput (locals),
mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()), mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()),
@ -32,7 +32,7 @@ namespace Compiler
bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) 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(); mControlParser.reset();
if (mControlParser.parseKeyword (keyword, loc, scanner)) if (mControlParser.parseKeyword (keyword, loc, scanner))
@ -71,6 +71,12 @@ namespace Compiler
if (code==Scanner::S_newline) // empty line if (code==Scanner::S_newline) // empty line
return true; 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(); mLineParser.reset();
if (mLineParser.parseSpecial (code, loc, scanner)) if (mLineParser.parseSpecial (code, loc, scanner))
scanner.scan (mLineParser); scanner.scan (mLineParser);

View file

@ -23,7 +23,7 @@ namespace Compiler
public: public:
/// \param end of script is marked by end keyword. /// \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); bool end = false);
void getCode (std::vector<Interpreter::Type_Code>& code) const; void getCode (std::vector<Interpreter::Type_Code>& code) const;

Some files were not shown because too many files have changed in this diff Show more