From 72fca4009057169a63b05da9ff86d5f75ec2f1b7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jun 2012 11:59:45 +0200 Subject: [PATCH 01/38] Issue #181: member variable access in interpreter context --- apps/openmw/mwscript/interpretercontext.cpp | 66 +++++++++++++++++++++ apps/openmw/mwscript/interpretercontext.hpp | 12 ++++ apps/openmw/mwscript/scriptmanager.cpp | 39 ++++++++++++ apps/openmw/mwscript/scriptmanager.hpp | 4 ++ components/interpreter/context.hpp | 13 ++++ 5 files changed, 134 insertions(+) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index a369486faf..55059b5224 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -270,6 +270,72 @@ namespace MWScript MWBase::Environment::get().getWorld()->disable (ref); } + int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + + return ptr.getRefData().getLocals().mShorts[index]; + } + + int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + + return ptr.getRefData().getLocals().mLongs[index]; + } + + float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + + return ptr.getRefData().getLocals().mFloats[index]; + } + + void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value) + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + + ptr.getRefData().getLocals().mShorts[index] = value; + } + + void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value) + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + + ptr.getRefData().getLocals().mLongs[index] = value; + } + + void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value) + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + + ptr.getRefData().getLocals().mFloats[index] = value; + } + MWWorld::Ptr InterpreterContext::getReference() { return getReference ("", true); diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 40f53337db..9fdc3c21a0 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -107,6 +107,18 @@ namespace MWScript virtual void disable (const std::string& id = ""); + virtual int getMemberShort (const std::string& id, const std::string& name) const; + + virtual int getMemberLong (const std::string& id, const std::string& name) const; + + virtual float getMemberFloat (const std::string& id, const std::string& name) const; + + virtual void setMemberShort (const std::string& id, const std::string& name, int value); + + virtual void setMemberLong (const std::string& id, const std::string& name, int value); + + virtual void setMemberFloat (const std::string& id, const std::string& name, float value); + MWWorld::Ptr getReference(); ///< Reference, that the script is running from (can be empty) }; diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 506cf049c4..6ae5064832 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -156,4 +156,43 @@ namespace MWScript { return mGlobalScripts; } + + int ScriptManager::getLocalIndex (const std::string& scriptId, const std::string& variable, + char type) + { + const ESM::Script *script = mStore.scripts.find (scriptId); + + int offset = 0; + int size = 0; + + switch (type) + { + case 's': + + offset = 0; + size = script->data.numShorts; + break; + + case 'l': + + offset = script->data.numShorts; + size = script->data.numLongs; + break; + + case 'f': + + offset = script->data.numShorts+script->data.numLongs; + size = script->data.numFloats; + + default: + + throw std::runtime_error ("invalid variable type"); + } + + for (int i=0; ivarNames.at (i+offset)==variable) + return i; + + throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); + } } diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index 35c1fadd9e..34cc0defec 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -67,6 +67,10 @@ namespace MWScript ///< Return locals for script \a name. GlobalScripts& getGlobalScripts(); + + int getLocalIndex (const std::string& scriptId, const std::string& variable, char type); + ///< Return index of the variable of the given name and type in the given script. Will + /// throw an exception, if there is no such script or variable or the type does not match. }; }; diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 973b22d350..4221da36ed 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -65,6 +65,19 @@ namespace Interpreter virtual void enable (const std::string& id = "") = 0; virtual void disable (const std::string& id = "") = 0; + + virtual int getMemberShort (const std::string& id, const std::string& name) const = 0; + + virtual int getMemberLong (const std::string& id, const std::string& name) const = 0; + + virtual float getMemberFloat (const std::string& id, const std::string& name) const = 0; + + virtual void setMemberShort (const std::string& id, const std::string& name, int value) = 0; + + virtual void setMemberLong (const std::string& id, const std::string& name, int value) = 0; + + virtual void setMemberFloat (const std::string& id, const std::string& name, float value) + = 0; }; } From ce43ff8d0520729e4d36e7b3fd40e7460d3e2909 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jun 2012 13:56:49 +0200 Subject: [PATCH 02/38] Issue #181: added member variable access opcodes --- components/interpreter/docs/vmformat.txt | 8 +- components/interpreter/installopcodes.cpp | 6 + components/interpreter/localopcodes.hpp | 217 ++++++++++++++++------ 3 files changed, 178 insertions(+), 53 deletions(-) diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 3e513aa44e..91e0c060e7 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -121,5 +121,11 @@ op 58: report string literal index in stack[0]; additional arguments (if any) in stack[n]..stack[1]; n is determined according to the message string all arguments are removed from stack -opcodes 59-33554431 unused +op 59: store stack[0] in member short stack[2] of object with ID stack[1] +op 60: store stack[0] in member long stack[2] of object with ID stack[1] +op 61: store stack[0] in member float stack[2] of object with ID stack[1] +op 62: replace stack[0] with member short stack[1] of object with ID stack[0] +op 63: replace stack[0] with member short stack[1] of object with ID stack[0] +op 64: replace stack[0] with member short stack[1] of object with ID stack[0] +opcodes 65-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 556477af25..05f71f1cca 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -40,6 +40,12 @@ namespace Interpreter interpreter.installSegment5 (42, new OpFetchGlobalShort); interpreter.installSegment5 (43, new OpFetchGlobalLong); interpreter.installSegment5 (44, new OpFetchGlobalFloat); + interpreter.installSegment5 (59, new OpStoreMemberShort); + interpreter.installSegment5 (60, new OpStoreMemberLong); + interpreter.installSegment5 (61, new OpStoreMemberFloat); + interpreter.installSegment5 (62, new OpFetchMemberShort); + interpreter.installSegment5 (63, new OpFetchMemberLong); + interpreter.installSegment5 (64, new OpFetchMemberFloat); // math interpreter.installSegment5 (9, new OpAddInt); diff --git a/components/interpreter/localopcodes.hpp b/components/interpreter/localopcodes.hpp index ea62b7ad89..852fa7099b 100644 --- a/components/interpreter/localopcodes.hpp +++ b/components/interpreter/localopcodes.hpp @@ -6,11 +6,11 @@ #include "context.hpp" namespace Interpreter -{ +{ class OpStoreLocalShort : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -20,13 +20,13 @@ namespace Interpreter runtime.pop(); runtime.pop(); - } + } }; - + class OpStoreLocalLong : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -36,13 +36,13 @@ namespace Interpreter runtime.pop(); runtime.pop(); - } - }; - + } + }; + class OpStoreLocalFloat : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Float data = runtime[0].mFloat; @@ -52,71 +52,71 @@ namespace Interpreter runtime.pop(); runtime.pop(); - } + } }; - + class OpFetchIntLiteral : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer intValue = runtime.getIntegerLiteral (runtime[0].mInteger); runtime[0].mInteger = intValue; - } - }; - + } + }; + class OpFetchFloatLiteral : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Float floatValue = runtime.getFloatLiteral (runtime[0].mInteger); runtime[0].mFloat = floatValue; - } - }; - + } + }; + class OpFetchLocalShort : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { int index = runtime[0].mInteger; int value = runtime.getContext().getLocalShort (index); runtime[0].mInteger = value; - } - }; + } + }; class OpFetchLocalLong : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { - int index = runtime[0].mInteger; + int index = runtime[0].mInteger; int value = runtime.getContext().getLocalLong (index); runtime[0].mInteger = value; - } - }; + } + }; class OpFetchLocalFloat : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { int index = runtime[0].mInteger; float value = runtime.getContext().getLocalFloat (index); runtime[0].mFloat = value; - } - }; - + } + }; + class OpStoreGlobalShort : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -128,13 +128,13 @@ namespace Interpreter runtime.pop(); runtime.pop(); - } + } }; - + class OpStoreGlobalLong : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -146,13 +146,13 @@ namespace Interpreter runtime.pop(); runtime.pop(); - } - }; - + } + }; + class OpStoreGlobalFloat : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Float data = runtime[0].mFloat; @@ -164,48 +164,161 @@ namespace Interpreter runtime.pop(); runtime.pop(); - } + } }; - + class OpFetchGlobalShort : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { - int index = runtime[0].mInteger; + int index = runtime[0].mInteger; std::string name = runtime.getStringLiteral (index); Type_Integer value = runtime.getContext().getGlobalShort (name); runtime[0].mInteger = value; - } - }; + } + }; class OpFetchGlobalLong : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { - int index = runtime[0].mInteger; + int index = runtime[0].mInteger; std::string name = runtime.getStringLiteral (index); Type_Integer value = runtime.getContext().getGlobalLong (name); runtime[0].mInteger = value; - } - }; + } + }; class OpFetchGlobalFloat : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { int index = runtime[0].mInteger; std::string name = runtime.getStringLiteral (index); Type_Float value = runtime.getContext().getGlobalFloat (name); runtime[0].mFloat = value; - } - }; + } + }; + + class OpStoreMemberShort : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer data = runtime[0].mInteger; + Type_Integer index = runtime[1].mInteger; + std::string id = runtime.getStringLiteral (index); + index = runtime[2].mInteger; + std::string variable = runtime.getStringLiteral (index); + + runtime.getContext().setMemberShort (id, variable, data); + + runtime.pop(); + runtime.pop(); + runtime.pop(); + } + }; + + class OpStoreMemberLong : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer data = runtime[0].mInteger; + Type_Integer index = runtime[1].mInteger; + std::string id = runtime.getStringLiteral (index); + index = runtime[2].mInteger; + std::string variable = runtime.getStringLiteral (index); + + runtime.getContext().setMemberLong (id, variable, data); + + runtime.pop(); + runtime.pop(); + runtime.pop(); + } + }; + + class OpStoreMemberFloat : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer index = runtime[0].mInteger; + std::string id = runtime.getStringLiteral (index); + Type_Float data = runtime[1].mFloat; + index = runtime[2].mInteger; + std::string variable = runtime.getStringLiteral (index); + + runtime.getContext().setMemberFloat (id, variable, data); + + runtime.pop(); + runtime.pop(); + runtime.pop(); + } + }; + + class OpFetchMemberShort : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer index = runtime[0].mInteger; + std::string id = runtime.getStringLiteral (index); + index = runtime[1].mInteger; + std::string variable = runtime.getStringLiteral (index); + runtime.pop(); + + index = runtime[0].mInteger; + int value = runtime.getContext().getMemberShort (id, variable); + runtime[0].mInteger = value; + } + }; + + class OpFetchMemberLong : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer index = runtime[0].mInteger; + std::string id = runtime.getStringLiteral (index); + index = runtime[1].mInteger; + std::string variable = runtime.getStringLiteral (index); + runtime.pop(); + + index = runtime[0].mInteger; + int value = runtime.getContext().getMemberLong (id, variable); + runtime[0].mInteger = value; + } + }; + + class OpFetchMemberFloat : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + Type_Integer index = runtime[0].mInteger; + std::string id = runtime.getStringLiteral (index); + index = runtime[1].mInteger; + std::string variable = runtime.getStringLiteral (index); + runtime.pop(); + + index = runtime[0].mInteger; + float value = runtime.getContext().getMemberFloat (id, variable); + runtime[0].mFloat = value; + } + }; } #endif - From 7354d1eccb4dcd6a432ca88588c1d0ada911d72a Mon Sep 17 00:00:00 2001 From: Sylvain THESNIERES Date: Fri, 8 Jun 2012 19:54:12 +0200 Subject: [PATCH 03/38] CMake fixes: - Fix environment variable in Bullet - Remove spurious message in MyGUI --- cmake/FindBullet.cmake | 2 ++ cmake/FindMyGUI.cmake | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 552a0651af..8d5ea2f1e5 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -19,6 +19,8 @@ # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. +set(BULLET_ROOT $ENV{BULLET_ROOT}) + macro(_FIND_BULLET_LIBRARY _var) find_library(${_var} NAMES diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index c79ee5998c..7278fe2007 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -22,7 +22,7 @@ IF (WIN32) #Windows SET(MYGUISDK $ENV{MYGUI_HOME}) IF (MYGUISDK) findpkg_begin ( "MYGUI" ) - MESSAGE(STATUS "Using MyGUI in OGRE SDK") + MESSAGE(STATUS "Using MyGUI in MyGUI SDK") STRING(REGEX REPLACE "[\\]" "/" MYGUISDK "${MYGUISDK}" ) find_path ( MYGUI_INCLUDE_DIRS @@ -35,7 +35,7 @@ MyGUI_OgrePlatform.h "${MYGUISDK}/Platforms/Ogre/OgrePlatform/include" NO_DEFAULT_PATH ) -SET ( MYGUI_LIB_DIR ${MYGUISDK}/*/lib ) +SET ( MYGUI_LIB_DIR ${MYGUISDK}/lib ${MYGUISDK}/*/lib ) find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine.lib @@ -69,7 +69,7 @@ make_library_set ( MYGUI_PLATFORM_LIBRARIES ) MESSAGE ("${MYGUI_LIBRARIES}") MESSAGE ("${MYGUI_PLATFORM_LIBRARIES}") -findpkg_finish ( "MYGUI" ) +#findpkg_finish ( "MYGUI" ) ENDIF (MYGUISDK) IF (OGRESOURCE) From fc3a3fc173ce4dc04685bb9ced2e0e4faf0fb556 Mon Sep 17 00:00:00 2001 From: Sylvain THESNIERES Date: Fri, 8 Jun 2012 19:55:39 +0200 Subject: [PATCH 04/38] MSVC build compliance: - static const float member is not ISO - callback do not match DLL signature --- apps/openmw/mwgui/settingswindow.hpp | 8 ++++---- apps/openmw/mwsound/audiere_decoder.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index ce95edbd2e..e3827c7b03 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -16,10 +16,10 @@ namespace MWGui SettingsWindow(WindowManager& parWindowManager); private: - static const float sFovMin = 30; - static const float sFovMax = 140; - static const float sViewDistMin = 2000; - static const float sViewDistMax = 5600; + static int const sFovMin = 30; + static int const sFovMax = 140; + static int const sViewDistMin = 2000; + static int const sViewDistMax = 5600; protected: MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwsound/audiere_decoder.cpp b/apps/openmw/mwsound/audiere_decoder.cpp index acc2e5283c..4e73573a74 100644 --- a/apps/openmw/mwsound/audiere_decoder.cpp +++ b/apps/openmw/mwsound/audiere_decoder.cpp @@ -41,8 +41,8 @@ class OgreFile : public audiere::File } size_t refs; - virtual void ref() { ++refs; } - virtual void unref() + ADR_METHOD(void) ref() { ++refs; } + ADR_METHOD(void) unref() { if(--refs == 0) delete this; From 0c7476b88c91f7143708d17c1f63a658846d0d39 Mon Sep 17 00:00:00 2001 From: Sylvain THESNIERES Date: Fri, 8 Jun 2012 19:56:27 +0200 Subject: [PATCH 05/38] Fix build in DEBUG mode for MSVC - commented stall code --- libs/openengine/bullet/pmove.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 591f1869f8..5cf0951c01 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -1833,13 +1833,13 @@ void PmoveSingle (playerMove* const pmove) pml.hasWater = pmove->hasWater; pml.isInterior = pmove->isInterior; pml.waterHeight = pmove->waterHeight; -#ifdef _DEBUG - if (!pml.traceObj) - __debugbreak(); - - if (!pml.traceObj->incellptr) - __debugbreak(); -#endif +//#ifdef _DEBUG + //if (!pml.traceObj) + // __debugbreak(); + // + //if (!pml.traceObj->incellptr) + // __debugbreak(); +//#endif // determine the time pml.msec = pmove->cmd.serverTime - pm->ps.commandTime; From 0bcec32c70dceb33142302a2ee7048b6bb3e0881 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Jun 2012 02:50:29 +0200 Subject: [PATCH 06/38] Changed launcher logo to the new one done by Necrod --- .../resources/images/openmw-header.png | Bin 50727 -> 51091 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/launcher/resources/images/openmw-header.png b/apps/launcher/resources/images/openmw-header.png index a2ffab68b8b447193d1153950e5c4d7f43348641..98c0cbe6fd3d52dbb24a844a235328aa676d365a 100644 GIT binary patch literal 51091 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 A@c;k- literal 50727 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 Ai~s-t From 82fba53771b6048d80f268a6d36b51cd2455b7cb Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 13 Jun 2012 14:58:27 +0200 Subject: [PATCH 07/38] Removed the license screen and changed so all licenses are instead installed to the game folder. --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e11ad0c0ab..b83935bdcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -370,6 +370,10 @@ if(WIN32) INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" "${OpenMW_SOURCE_DIR}/readme.txt" + "${OpenMW_SOURCE_DIR}/GPL3.txt" + "${OpenMW_SOURCE_DIR}/OFL.txt" + "${OpenMW_SOURCE_DIR}/Bitstream Vera License.txt" + "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" @@ -391,8 +395,8 @@ if(WIN32) !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\" ") + SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") - SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") SET(CPACK_NSIS_DISPLAY_NAME "OpenMW") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") From 9f84518910a3dd8bdfb47435d9caadd819c962aa Mon Sep 17 00:00:00 2001 From: Sylvain THESNIERES Date: Thu, 14 Jun 2012 08:09:03 +0200 Subject: [PATCH 08/38] Remove dead code Object class is quake specific stuff and these parts were *dead*. There is more references to the pointer but it is commented and seems to be used as "reference code" for future implementation of player functions, so I prefered not touching them. --- libs/openengine/bullet/pmove.cpp | 10 ---------- libs/openengine/bullet/pmove.h | 1 - 2 files changed, 11 deletions(-) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 5cf0951c01..b723f67e47 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -15,8 +15,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. //#include "GameTime.h" -//#include "Object.h" - //#include "Sound.h" //#include "..\..\ESMParser\ESMParser\SNDG.h" @@ -68,7 +66,6 @@ static struct playermoveLocal int waterHeight; bool hasWater; bool isInterior; - //Object* traceObj; } pml; @@ -1833,13 +1830,6 @@ void PmoveSingle (playerMove* const pmove) pml.hasWater = pmove->hasWater; pml.isInterior = pmove->isInterior; pml.waterHeight = pmove->waterHeight; -//#ifdef _DEBUG - //if (!pml.traceObj) - // __debugbreak(); - // - //if (!pml.traceObj->incellptr) - // __debugbreak(); -//#endif // determine the time pml.msec = pmove->cmd.serverTime - pm->ps.commandTime; diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index e46eb9d2e7..6cedd35995 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -190,7 +190,6 @@ struct playerMove int waterHeight; bool hasWater; bool isInterior; - //Object* traceObj; OEngine::Physic::PhysicEngine* mEngine; }; From e4984955894d5c0593e966f454bda5bb7d095dec Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jun 2012 21:27:55 +0200 Subject: [PATCH 09/38] fix a leak: physics heightfield was only destroyed on cell change and not on exit --- libs/openengine/bullet/physic.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index a94434e5b5..354b4d5897 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -222,6 +222,14 @@ namespace Physic PhysicEngine::~PhysicEngine() { + HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); + for (; hf_it != mHeightFieldMap.end(); ++hf_it) + { + dynamicsWorld->removeRigidBody(hf_it->second.mBody); + delete hf_it->second.mShape; + delete hf_it->second.mBody; + } + RigidBodyContainer::iterator rb_it = RigidBodyMap.begin(); for (; rb_it != RigidBodyMap.end(); ++rb_it) { From 0b850a2cb5280114fd003b3b8f6d6c899e9fb11b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Jun 2012 09:15:37 +0200 Subject: [PATCH 10/38] fix crash introduced by last commit --- libs/openengine/bullet/physic.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 354b4d5897..f7caa54b49 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -328,6 +328,8 @@ namespace Physic dynamicsWorld->removeRigidBody(hf.mBody); delete hf.mShape; delete hf.mBody; + + mHeightFieldMap.erase(name); } RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale) From 7caf72760624d0b84bc83bf18028db3989776599 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 Jun 2012 17:43:23 +0200 Subject: [PATCH 11/38] added new contributor to readme file --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 513474dd64..4cc31343b0 100644 --- a/readme.txt +++ b/readme.txt @@ -110,6 +110,7 @@ Nikolay “corristo” Kasyanov Pieter “pvdk” van der Kloet Roman "Kromgart" Melnik Sebastian “swick” Wick +Sylvain "Garvek" T. Retired Developers: Ardekantur From 050559d2e2f20883faa15aa7426369d0189d8627 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 10:31:33 +0200 Subject: [PATCH 12/38] Issue #181: added member variable access token --- components/compiler/scanner.cpp | 2 ++ components/compiler/scanner.hpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index d0397e8cf1..962699dfa4 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -360,6 +360,8 @@ namespace Compiler special = S_open; else if (c==')') special = S_close; + else if (c=='.') + special = S_member; else if (c=='=') { if (get (c)) diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 53cb92ef26..19f4ca96ad 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -65,7 +65,8 @@ namespace Compiler S_cmpEQ, S_cmpNE, S_cmpLT, S_cmpLE, S_cmpGT, S_cmpGE, S_plus, S_minus, S_mult, S_div, S_comma, - S_ref + S_ref, + S_member }; private: From d1441d79e7611f7a226a816b317bc005b217b048 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 10:49:34 +0200 Subject: [PATCH 13/38] Issue #181: added code generation for member variable access --- components/compiler/generator.cpp | 112 +++++++++++++++++++++++++++++- components/compiler/generator.hpp | 6 ++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 26a80387b1..b619ad67a3 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -260,6 +260,36 @@ namespace code.push_back (Compiler::Generator::segment5 (44)); } + void opStoreMemberShort (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (59)); + } + + void opStoreMemberLong (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (60)); + } + + void opStoreMemberFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (61)); + } + + void opFetchMemberShort (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (62)); + } + + void opFetchMemberLong (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (63)); + } + + void opFetchMemberFloat (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (64)); + } + void opRandom (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (45)); @@ -644,7 +674,7 @@ namespace Compiler if (localType!=valueType) { - if (localType=='f' && valueType=='l') + if (localType=='f' && (valueType=='l' || valueType=='s')) { opIntToFloat (code); } @@ -707,6 +737,86 @@ namespace Compiler } } + void assignToMember (CodeContainer& code, Literals& literals, char localType, + const std::string& name, const std::string& id, const CodeContainer& value, char valueType) + { + int index = literals.addString (name); + + opPushInt (code, index); + + index = literals.addString (id); + + opPushInt (code, index); + + std::copy (value.begin(), value.end(), std::back_inserter (code)); + + if (localType!=valueType) + { + if (localType=='f' && (valueType=='l' || valueType=='s')) + { + opIntToFloat (code); + } + else if ((localType=='l' || localType=='s') && valueType=='f') + { + opFloatToInt (code); + } + } + + switch (localType) + { + case 'f': + + opStoreMemberFloat (code); + break; + + case 's': + + opStoreMemberShort (code); + break; + + case 'l': + + opStoreMemberLong (code); + break; + + default: + + assert (0); + } + } + + void fetchMember (CodeContainer& code, Literals& literals, char localType, + const std::string& name, const std::string& id) + { + int index = literals.addString (name); + + opPushInt (code, index); + + index = literals.addString (id); + + switch (localType) + { + case 'f': + + opFetchMemberFloat (code); + break; + + case 's': + + opFetchMemberShort (code); + break; + + case 'l': + + opFetchMemberLong (code); + break; + + default: + + assert (0); + } + } + void random (CodeContainer& code) { opRandom (code); diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index 89e1984314..feab26c93d 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -101,6 +101,12 @@ namespace Compiler void fetchGlobal (CodeContainer& code, Literals& literals, char localType, const std::string& name); + void assignToMember (CodeContainer& code, Literals& literals, char memberType, + const std::string& name, const std::string& id, const CodeContainer& value, char valueType); + + void fetchMember (CodeContainer& code, Literals& literals, char memberType, + const std::string& name, const std::string& id); + void random (CodeContainer& code); void scriptRunning (CodeContainer& code); From 6a89d76321f415942872f9c4bbdbb4e7c43f49a7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 11:52:35 +0200 Subject: [PATCH 14/38] Issue #181: Improved script error reporting for local and global scripts --- apps/openmw/mwscript/scriptmanager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 6ae5064832..67414a06fd 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "extensions.hpp" @@ -46,8 +47,13 @@ namespace MWScript if (!mErrorHandler.isGood()) Success = false; } - catch (...) + catch (const Compiler::SourceException&) { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + std::cerr << "An exception has been thrown: " << error.what() << std::endl; Success = false; } From 6c5b21fa42dcd7e66ff8640e146cbb0fc86e3649 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 13:06:23 +0200 Subject: [PATCH 15/38] Issue #181: Member variable access in expressions; error reporting fix for the previous commit --- apps/openmw/mwscript/compilercontext.cpp | 14 +++++++++ apps/openmw/mwscript/compilercontext.hpp | 3 ++ apps/openmw/mwscript/scriptmanager.cpp | 4 +++ components/compiler/context.hpp | 20 +++++++------ components/compiler/exprparser.cpp | 37 ++++++++++++++++++++++-- components/compiler/exprparser.hpp | 3 ++ 6 files changed, 70 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 078d0da5e7..0a6ffd0c7a 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -5,6 +5,8 @@ #include "../mwworld/world.hpp" +#include "scriptmanager.hpp" + namespace MWScript { CompilerContext::CompilerContext (Type type) @@ -21,6 +23,18 @@ namespace MWScript return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); } + char CompilerContext::getMemberType (const std::string& name, const std::string& id) const + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); + + std::string script = MWWorld::Class::get (ptr).getScript (ptr); + + if (script.empty()) + return ' '; + + return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + } + bool CompilerContext::isId (const std::string& name) const { return diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 32b2f1881c..5ec98e09a7 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -30,6 +30,9 @@ namespace MWScript /// 'l: long, 's': short, 'f': float, ' ': does not exist. virtual char getGlobalType (const std::string& name) const; + virtual char getMemberType (const std::string& name, const std::string& id) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? }; diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 67414a06fd..d8bd269c69 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -50,6 +50,7 @@ namespace MWScript catch (const Compiler::SourceException&) { // error has already been reported via error handler + Success = false; } catch (const std::exception& error) { @@ -146,6 +147,9 @@ namespace MWScript { if (!compile (name)) { + /// \todo Handle case of cyclic member variable access. Currently this could look up + /// the whole application in an endless recursion. + // failed -> ignore script from now on. std::vector empty; mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); diff --git a/components/compiler/context.hpp b/components/compiler/context.hpp index 929119cf40..1b02613c59 100644 --- a/components/compiler/context.hpp +++ b/components/compiler/context.hpp @@ -10,33 +10,35 @@ namespace Compiler class Context { const Extensions *mExtensions; - + public: - + Context() : mExtensions (0) {} - + virtual ~Context() {} - + virtual bool canDeclareLocals() const = 0; ///< Is the compiler allowed to declare local variables? - + void setExtensions (const Extensions *extensions = 0) { mExtensions = extensions; } - + const Extensions *getExtensions() const { return mExtensions; } - + virtual char getGlobalType (const std::string& name) const = 0; ///< 'l: long, 's': short, 'f': float, ' ': does not exist. - + + virtual char getMemberType (const std::string& name, const std::string& id) const = 0; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual bool isId (const std::string& name) const = 0; ///< Does \a name match an ID, that can be referenced? }; } #endif - diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 95480c0239..8041a7c8af 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -195,10 +195,31 @@ namespace Compiler return parseArguments (arguments, scanner, mCode); } + bool ExprParser::handleMemberAccess (const std::string& name) + { + mMemberOp = false; + + std::string name2 = toLower (name); + std::string id = toLower (mExplicit); + + char type = getContext().getMemberType (name2, id); + + if (type!=' ') + { + Generator::fetchMember (mCode, mLiterals, type, name2, id); + mNextOperand = false; + mExplicit.clear(); + mOperands.push_back (type=='f' ? 'f' : 'l'); + return true; + } + + return false; + } + ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, Literals& literals, bool argument) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), - mNextOperand (true), mFirst (true), mArgument (argument) + mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false) {} bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) @@ -251,7 +272,12 @@ namespace Compiler Scanner& scanner) { if (!mExplicit.empty()) + { + if (mMemberOp && handleMemberAccess (name)) + return true; + return Parser::parseName (name, loc, scanner); + } mFirst = false; @@ -281,7 +307,7 @@ namespace Compiler return true; } - if (mExplicit.empty() && getContext().isId (name)) + if (mExplicit.empty() && getContext().isId (name2)) { mExplicit = name; return true; @@ -497,6 +523,12 @@ namespace Compiler return true; } + if (!mMemberOp && code==Scanner::S_member) + { + mMemberOp = true; + return true; + } + return Parser::parseSpecial (code, loc, scanner); } @@ -609,6 +641,7 @@ namespace Compiler mFirst = true; mExplicit.clear(); mRefOp = false; + mMemberOp = false; Parser::reset(); } diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 87945c6280..8ce5409d23 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -26,6 +26,7 @@ namespace Compiler bool mArgument; std::string mExplicit; bool mRefOp; + bool mMemberOp; int getPriority (char op) const; @@ -53,6 +54,8 @@ namespace Compiler int parseArguments (const std::string& arguments, Scanner& scanner); + bool handleMemberAccess (const std::string& name); + public: ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, From 8b19de17b6371d4cb2afa647c39dca69209b24eb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 13:21:01 +0200 Subject: [PATCH 16/38] Iisue #181: enable member variable access from expressions in console --- components/compiler/lineparser.cpp | 17 ++++++++++++++++- components/compiler/lineparser.hpp | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 834cd27b48..db21cce9bb 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -18,7 +18,10 @@ namespace Compiler if (!mExplicit.empty()) { mExprParser.parseName (mExplicit, loc, scanner); - mExprParser.parseSpecial (Scanner::S_ref, loc, scanner); + if (mState==MemberState) + mExprParser.parseSpecial (Scanner::S_member, loc, scanner); + else + mExprParser.parseSpecial (Scanner::S_ref, loc, scanner); } scanner.scan (mExprParser); @@ -256,6 +259,7 @@ namespace Compiler { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); + mState = EndState; return true; } @@ -269,6 +273,7 @@ namespace Compiler { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); + mState = EndState; return true; } } @@ -342,6 +347,7 @@ namespace Compiler { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); + mState = EndState; return true; } } @@ -366,6 +372,14 @@ namespace Compiler return true; } + if (code==Scanner::S_member && mState==PotentialExplicitState) + { + mState = MemberState; + parseExpression (scanner, loc); + mState = EndState; + return true; + } + if (code==Scanner::S_newline && mState==MessageButtonState) { Generator::message (mCode, mLiterals, mName, mButtons); @@ -383,6 +397,7 @@ namespace Compiler { scanner.putbackSpecial (code, loc); parseExpression (scanner, loc); + mState = EndState; return true; } diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 531b7762f0..6f331b7bf2 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -24,7 +24,7 @@ namespace Compiler SetState, SetLocalVarState, SetGlobalVarState, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, EndState, - PotentialExplicitState, ExplicitState + PotentialExplicitState, ExplicitState, MemberState }; Locals& mLocals; From 10b27e582b5e0959db0219e91aa82aa7a9d5f567 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 13:51:13 +0200 Subject: [PATCH 17/38] Issue #181: various fixed to member variable access --- apps/openmw/mwscript/interpretercontext.cpp | 12 ++++++++++++ components/compiler/generator.cpp | 2 ++ components/interpreter/localopcodes.hpp | 3 --- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 55059b5224..152fcf85cb 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -278,6 +278,8 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); return ptr.getRefData().getLocals().mShorts[index]; } @@ -289,6 +291,8 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); return ptr.getRefData().getLocals().mLongs[index]; } @@ -300,6 +304,8 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); return ptr.getRefData().getLocals().mFloats[index]; } @@ -311,6 +317,8 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); ptr.getRefData().getLocals().mShorts[index] = value; } @@ -322,6 +330,8 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); ptr.getRefData().getLocals().mLongs[index] = value; } @@ -333,6 +343,8 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); ptr.getRefData().getLocals().mFloats[index] = value; } diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index b619ad67a3..9b02e4273f 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -794,6 +794,8 @@ namespace Compiler index = literals.addString (id); + opPushInt (code, index); + switch (localType) { case 'f': diff --git a/components/interpreter/localopcodes.hpp b/components/interpreter/localopcodes.hpp index 852fa7099b..4b0edff9cb 100644 --- a/components/interpreter/localopcodes.hpp +++ b/components/interpreter/localopcodes.hpp @@ -278,7 +278,6 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - index = runtime[0].mInteger; int value = runtime.getContext().getMemberShort (id, variable); runtime[0].mInteger = value; } @@ -296,7 +295,6 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - index = runtime[0].mInteger; int value = runtime.getContext().getMemberLong (id, variable); runtime[0].mInteger = value; } @@ -314,7 +312,6 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - index = runtime[0].mInteger; float value = runtime.getContext().getMemberFloat (id, variable); runtime[0].mFloat = value; } From fe85de5ea7d7cebf0d09ffccfc7a5f9e76a34caf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 14:29:55 +0200 Subject: [PATCH 18/38] Issue #181: assignment to member variables --- components/compiler/lineparser.cpp | 39 +++++++++++++++++++++++-- components/compiler/lineparser.hpp | 4 ++- components/interpreter/localopcodes.hpp | 4 +-- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index db21cce9bb..a4cbc1ffeb 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -113,12 +113,13 @@ namespace Compiler if (mState==SetState) { std::string name2 = toLower (name); + mName = name2; // local variable? char type = mLocals.getType (name2); if (type!=' ') { - mName = name2; + mType = type; mState = SetLocalVarState; return true; } @@ -126,12 +127,27 @@ namespace Compiler type = getContext().getGlobalType (name2); if (type!=' ') { - mName = name2; mType = type; mState = SetGlobalVarState; return true; } + mState = SetPotentialMemberVarState; + return true; + } + + if (mState==SetMemberVarState) + { + mMemberName = toLower (name); + char type = getContext().getMemberType (mMemberName, mName); + + if (type!=' ') + { + mState = SetMemberVarState2; + mType = type; + return true; + } + getErrorHandler().error ("unknown variable", loc); SkipParser skip (getErrorHandler(), getContext()); scanner.scan (skip); @@ -338,6 +354,19 @@ namespace Compiler mState = EndState; return true; } + else if (mState==SetMemberVarState2 && keyword==Scanner::K_to) + { + mExprParser.reset(); + scanner.scan (mExprParser); + + std::vector code; + char type = mExprParser.append (code); + + Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type); + + mState = EndState; + return true; + } if (mAllowExpression) { @@ -392,6 +421,12 @@ namespace Compiler return true; } + if (code==Scanner::S_member && mState==SetPotentialMemberVarState) + { + mState = SetMemberVarState; + return true; + } + if (mAllowExpression && mState==BeginState && (code==Scanner::S_open || code==Scanner::S_minus)) { diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 6f331b7bf2..aa74cd232f 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -21,7 +21,8 @@ namespace Compiler { BeginState, ShortState, LongState, FloatState, - SetState, SetLocalVarState, SetGlobalVarState, + SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, + SetMemberVarState, SetMemberVarState2, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, EndState, PotentialExplicitState, ExplicitState, MemberState @@ -32,6 +33,7 @@ namespace Compiler std::vector& mCode; State mState; std::string mName; + std::string mMemberName; int mButtons; std::string mExplicit; char mType; diff --git a/components/interpreter/localopcodes.hpp b/components/interpreter/localopcodes.hpp index 4b0edff9cb..731c16276d 100644 --- a/components/interpreter/localopcodes.hpp +++ b/components/interpreter/localopcodes.hpp @@ -252,9 +252,9 @@ namespace Interpreter virtual void execute (Runtime& runtime) { - Type_Integer index = runtime[0].mInteger; + Type_Float data = runtime[0].mFloat; + Type_Integer index = runtime[1].mInteger; std::string id = runtime.getStringLiteral (index); - Type_Float data = runtime[1].mFloat; index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); From 3167ae9473e49ad1720fd398329077db7d02ca54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 15:49:03 +0200 Subject: [PATCH 19/38] added force/clearforce instructions for run and sneak --- apps/openmw/mwscript/controlextensions.cpp | 87 ++++++++++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 10 ++- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 363a09b6bd..1a7b452465 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -11,7 +11,10 @@ #include "../mwworld/player.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "interpretercontext.hpp" +#include "ref.hpp" #include @@ -54,11 +57,71 @@ namespace MWScript } }; + template + class OpClearForceRun : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::Class::get (ptr).getNpcStats (ptr).mForceRun = false; + } + }; + + template + class OpForceRun : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::Class::get (ptr).getNpcStats (ptr).mForceRun = true; + } + }; + + template + class OpClearForceSneak : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::Class::get (ptr).getNpcStats (ptr).mForceSneak = false; + } + }; + + template + class OpForceSneak : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::Class::get (ptr).getNpcStats (ptr).mForceSneak = true; + } + }; + const int numberOfControls = 7; const int opcodeEnable = 0x200007e; const int opcodeDisable = 0x2000085; const int opcodeToggleCollision = 0x2000130; + const int opcodeClearForceRun = 0x2000154; + const int opcodeClearForceRunExplicit = 0x2000155; + const int opcodeForceRun = 0x2000156; + const int opcodeForceRunExplicit = 0x2000157; + const int opcodeClearForceSneak = 0x2000158; + const int opcodeClearForceSneakExplicit = 0x2000159; + const int opcodeForceSneak = 0x200015a; + const int opcodeForceSneakExplicit = 0x200015b; const char *controls[numberOfControls] = { @@ -79,6 +142,16 @@ namespace MWScript extensions.registerInstruction ("togglecollision", "", opcodeToggleCollision); extensions.registerInstruction ("tcl", "", opcodeToggleCollision); + + extensions.registerInstruction ("clearforcerun", "", opcodeClearForceRun, + opcodeClearForceRunExplicit); + extensions.registerInstruction ("forcerun", "", opcodeForceRun, + opcodeForceRunExplicit); + + extensions.registerInstruction ("clearforcesneak", "", opcodeClearForceSneak, + opcodeClearForceSneakExplicit); + extensions.registerInstruction ("forcesneak", "", opcodeForceSneak, + opcodeForceSneakExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -90,6 +163,20 @@ namespace MWScript } interpreter.installSegment5 (opcodeToggleCollision, new OpToggleCollision); + + interpreter.installSegment5 (opcodeClearForceRun, new OpClearForceRun); + interpreter.installSegment5 (opcodeForceRun, new OpForceRun); + interpreter.installSegment5 (opcodeClearForceSneak, new OpClearForceSneak); + interpreter.installSegment5 (opcodeForceSneak, new OpForceSneak); + + interpreter.installSegment5 (opcodeClearForceRunExplicit, + new OpClearForceRun); + interpreter.installSegment5 (opcodeForceRunExplicit, + new OpForceRun); + interpreter.installSegment5 (opcodeClearForceSneakExplicit, + new OpClearForceSneak); + interpreter.installSegment5 (opcodeForceSneakExplicit, + new OpForceSneak); } } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 4423f17cfb..eb13a87224 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -147,4 +147,12 @@ op 0x2000150: ForceGreeting, explicit reference op 0x2000151: ToggleFullHelp op 0x2000152: Goodbye op 0x2000153: DontSaveObject (left unimplemented) -opcodes 0x2000154-0x3ffffff unused +op 0x2000154: ClearForceRun +op 0x2000155: ClearForceRun, explicit reference +op 0x2000156: ForceRun +op 0x2000156: ForceRun, explicit reference +op 0x2000157: ClearForceSneak +op 0x2000158: ClearForceSneak, explicit reference +op 0x2000159: ForceSneak +op 0x200015a: ForceSneak, explicit reference +opcodes 0x200015b-0x3ffffff unused From b16157a618115214b3b5f19e1a49287470a5765c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 15:49:39 +0200 Subject: [PATCH 20/38] documentation fix --- apps/openmw/mwscript/docs/vmformat.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index eb13a87224..219af9a0b4 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -150,9 +150,9 @@ op 0x2000153: DontSaveObject (left unimplemented) op 0x2000154: ClearForceRun op 0x2000155: ClearForceRun, explicit reference op 0x2000156: ForceRun -op 0x2000156: ForceRun, explicit reference -op 0x2000157: ClearForceSneak -op 0x2000158: ClearForceSneak, explicit reference -op 0x2000159: ForceSneak -op 0x200015a: ForceSneak, explicit reference +op 0x2000157: ForceRun, explicit reference +op 0x2000158: ClearForceSneak +op 0x2000159: ClearForceSneak, explicit reference +op 0x200015a: ForceSneak +op 0x200015b: ForceSneak, explicit reference opcodes 0x200015b-0x3ffffff unused From 7454713a9be6fdfc4ede96f52b787423e941d4a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 16:06:15 +0200 Subject: [PATCH 21/38] addet provisional implementation of AiWander (doesn't do anything yet) --- apps/openmw/mwscript/aiextensions.cpp | 30 ++++++++++++++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 4 +++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index aa541e55d3..54a67a8cd3 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -88,7 +88,31 @@ namespace MWScript } }; + template + class OpAiWander : public Interpreter::Opcode1 + { + public: + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + +// Interpreter::Type_Float range = runtime[0].mFloat; + runtime.pop(); + +// Interpreter::Type_Float duration = runtime[0].mFloat; + runtime.pop(); + +// Interpreter::Type_Float time = runtime[0].mFloat; + runtime.pop(); + + // discard additional idle arguments for now + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i); interpreter.installSegment3 (opcodeAiEscort, new OpAiEscort); interpreter.installSegment3 (opcodeAiEscortExplicit, new OpAiEscort); + interpreter.installSegment3 (opcodeAiWander, new OpAiWander); + interpreter.installSegment3 (opcodeAiWanderExplicit, new OpAiWander); interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone); interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDone); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 219af9a0b4..7faba7f415 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -29,7 +29,9 @@ op 0x2000c: PCLowerRank op 0x2000d: PCJoinFaction op 0x2000e: PCGetRank implicit op 0x2000f: PCGetRank explicit -opcodes 0x20010-0x3ffff unused +op 0x20010: AiWander +op 0x20011: AiWander, explicit reference +opcodes 0x20012-0x3ffff unused Segment 4: (not implemented yet) From ea29b74bb439a9ea5a73210c60a2fe30705e0bb6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 16:17:42 +0200 Subject: [PATCH 22/38] added per NPC/creature basic AI-settings (hello, fight, flee, alarm) --- apps/openmw/mwclass/creature.cpp | 5 +++++ apps/openmw/mwclass/npc.cpp | 7 ++++++- apps/openmw/mwmechanics/creaturestats.hpp | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e33fd322a7..c9b43896b2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -57,6 +57,11 @@ namespace MWClass data->mCreatureStats.mLevel = ref->base->data.level; + data->mCreatureStats.mHello = ref->base->AI.hello; + data->mCreatureStats.mFight = ref->base->AI.fight; + data->mCreatureStats.mFlee = ref->base->AI.flee; + data->mCreatureStats.mAlarm = ref->base->AI.alarm; + // store ptr.getRefData().setCustomData (data.release()); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4c964c7007..f30e164f96 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -70,12 +70,12 @@ namespace MWClass } } + // creature stats if(ref->base->npdt52.gold != -10) { for (int i=0; i<27; ++i) data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]); - // creature stats data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence); data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower); @@ -95,6 +95,11 @@ namespace MWClass /// \todo do something with npdt12 maybe:p } + data->mCreatureStats.mHello = ref->base->AI.hello; + data->mCreatureStats.mFight = ref->base->AI.fight; + data->mCreatureStats.mFlee = ref->base->AI.flee; + data->mCreatureStats.mAlarm = ref->base->AI.alarm; + // store ptr.getRefData().setCustomData (data.release()); } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index cc3c409da2..8d40e19423 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -19,6 +19,10 @@ namespace MWMechanics Spells mSpells; ActiveSpells mActiveSpells; MagicEffects mMagicEffects; + int mHello; + int mFight; + int mFlee; + int mAlarm; }; } From 8283f5f13597420ab83417951c89498ffa2043ef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 16:31:32 +0200 Subject: [PATCH 23/38] added setHello/Fight/Flee/Alarm instructions --- apps/openmw/mwscript/aiextensions.cpp | 88 ++++++++++++++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 10 ++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 54a67a8cd3..08b1f6f8cf 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwmechanics/creaturestats.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -114,6 +116,71 @@ namespace MWScript } }; + template + class OpSetHello : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).mHello = value; + } + }; + + template + class OpSetFight : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).mFight = value; + } + }; + + template + class OpSetFlee : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).mFlee = value; + } + }; + + template + class OpSetAlarm : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).mAlarm = value; + } + }; + + const int opcodeAiTravel = 0x20000; const int opcodeAiTravelExplicit = 0x20001; const int opcodeAiEscort = 0x20002; @@ -122,6 +189,14 @@ namespace MWScript const int opcodeGetAiPackageDoneExplicit = 0x200007d; const int opcodeAiWander = 0x20010; const int opcodeAiWanderExplicit = 0x20011; + const int opcodeSetHello = 0x200015e; + const int opcodeSetHelloExplicit = 0x200015d; + const int opcodeSetFight = 0x200015e; + const int opcodeSetFightExplicit = 0x200015f; + const int opcodeSetFlee = 0x2000160; + const int opcodeSetFleeExplicit = 0x2000161; + const int opcodeSetAlarm = 0x2000162; + const int opcodeSetAlarmExplicit = 0x2000163; void registerExtensions (Compiler::Extensions& extensions) { @@ -134,6 +209,11 @@ namespace MWScript extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone, opcodeGetAiPackageDoneExplicit); + + extensions.registerInstruction ("sethello", "l", opcodeSetHello, opcodeSetHelloExplicit); + extensions.registerInstruction ("setfight", "l", opcodeSetFight, opcodeSetFightExplicit); + extensions.registerInstruction ("setflee", "l", opcodeSetFlee, opcodeSetFleeExplicit); + extensions.registerInstruction ("setalarm", "l", opcodeSetAlarm, opcodeSetAlarmExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -147,6 +227,14 @@ namespace MWScript interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone); interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDone); + interpreter.installSegment5 (opcodeSetHello, new OpSetHello); + interpreter.installSegment5 (opcodeSetHelloExplicit, new OpSetHello); + interpreter.installSegment5 (opcodeSetFight, new OpSetFight); + interpreter.installSegment5 (opcodeSetFightExplicit, new OpSetFight); + interpreter.installSegment5 (opcodeSetFlee, new OpSetFlee); + interpreter.installSegment5 (opcodeSetFleeExplicit, new OpSetFlee); + interpreter.installSegment5 (opcodeSetAlarm, new OpSetAlarm); + interpreter.installSegment5 (opcodeSetAlarmExplicit, new OpSetAlarm); } } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7faba7f415..8a166eff3a 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -157,4 +157,12 @@ op 0x2000158: ClearForceSneak op 0x2000159: ClearForceSneak, explicit reference op 0x200015a: ForceSneak op 0x200015b: ForceSneak, explicit reference -opcodes 0x200015b-0x3ffffff unused +op 0x200015c: SetHello +op 0x200015d: SetHello, explicit reference +op 0x200015e: SetFight +op 0x200015f: SetFight, explicit reference +op 0x2000160: SetFlee +op 0x2000161: SetFlee, explicit reference +op 0x2000162: SetAlarm +op 0x2000163: SetAlarm, explicit reference +opcodes 0x2000164-0x3ffffff unused From e2a77037ebf88bd014df905bbf8515291ce59d8e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 16:38:54 +0200 Subject: [PATCH 24/38] fixed a type in a script instruction --- apps/openmw/mwscript/guiextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index b267cc6e49..8e5897298b 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -104,7 +104,7 @@ namespace MWScript extensions.registerInstruction ("enableclassmenu", "", opcodeEnableClassMenu); extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu); extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu); - extensions.registerInstruction ("enablestatsreviewmenu", "", + extensions.registerInstruction ("enablestatreviewmenu", "", opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu); From 3c42a71dae5e766d79a7e7b65b321804ce4db022 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Jun 2012 16:42:35 +0200 Subject: [PATCH 25/38] removed some cout spam --- apps/openmw/mwgui/messagebox.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 0bb7d3c1cf..27e14ba82b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -86,13 +86,12 @@ void MessageBoxManager::createMessageBox (const std::string& message) bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) { + /// \todo Don't write this kind of error message to cout. Either discard the old message box + /// silently or throw an exception. if(mInterMessageBoxe != NULL) { std::cout << "there is a MessageBox already" << std::endl; return false; } - std::cout << "interactive MessageBox: " << message << " - "; - std::copy (buttons.begin(), buttons.end(), std::ostream_iterator (std::cout, ", ")); - std::cout << std::endl; mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); From b831c3313dc3a16796760c42d3c3819c6ab61972 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Jun 2012 00:47:45 +0200 Subject: [PATCH 26/38] render system was not written on launcher exit --- apps/launcher/graphicspage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index e156e4fbc2..e6940164ea 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -200,6 +200,7 @@ void GraphicsPage::writeConfig() Settings::Manager::setBool("vsync", "Video", mVSyncCheckBox->checkState()); Settings::Manager::setBool("fullscreen", "Video", mFullScreenCheckBox->checkState()); Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString()); + Settings::Manager::setString("render system", "Video", mRendererComboBox->currentText().toStdString()); std::string resolution = mResolutionComboBox->currentText().toStdString(); // parse resolution x and y from a string like "800 x 600" From f81e1277013494850cd97a7d24b013101165300d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 17 Jun 2012 06:46:23 +0200 Subject: [PATCH 27/38] Created custom directory dialog which only accepts Data Files dirs --- apps/launcher/CMakeLists.txt | 3 ++ apps/launcher/datafilespage.cpp | 46 ++++++++++++++------------ apps/launcher/filedialog.cpp | 57 +++++++++++++++++++++++++++++++++ apps/launcher/filedialog.hpp | 50 +++++++++++++++++++++++++++++ apps/launcher/lineedit.cpp | 35 ++++++++------------ apps/launcher/lineedit.hpp | 2 +- 6 files changed, 150 insertions(+), 43 deletions(-) create mode 100644 apps/launcher/filedialog.cpp create mode 100644 apps/launcher/filedialog.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index ccefee1ee8..ed3559fdca 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -8,6 +8,7 @@ set(LAUNCHER playpage.cpp pluginsmodel.cpp pluginsview.cpp + filedialog.cpp launcher.rc ) @@ -22,6 +23,7 @@ set(LAUNCHER_HEADER playpage.hpp pluginsmodel.hpp pluginsview.hpp + filedialog.hpp ) # Headers that must be pre-processed @@ -34,6 +36,7 @@ set(LAUNCHER_HEADER_MOC playpage.hpp pluginsmodel.hpp pluginsview.hpp + filedialog.hpp ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index c15274e749..a4992bc630 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -5,6 +5,7 @@ #include "datafilespage.hpp" #include "lineedit.hpp" +#include "filedialog.hpp" #include "naturalsort.hpp" #include "pluginsmodel.hpp" #include "pluginsview.hpp" @@ -203,8 +204,7 @@ void DataFilesPage::setupDataFiles() mCfgMgr.readConfiguration(variables, desc); // Put the paths in a boost::filesystem vector to use with Files::Collections - Files::PathContainer dataDirs(variables["data"].as()); - mDataDirs = dataDirs; + mDataDirs = Files::PathContainer(variables["data"].as()); // std::string local = variables["data-local"].as(); // if (!local.empty()) { @@ -212,36 +212,42 @@ void DataFilesPage::setupDataFiles() // dataDirs.push_back(Files::PathContainer::value_type(local)); // } - if (dataDirs.size()>1) - dataDirs.resize (1); + if (mDataDirs.size()>1) + mDataDirs.resize (1); - mCfgMgr.processPaths(dataDirs); - - while (dataDirs.empty()) { - // No valid data files directory found + mCfgMgr.processPaths(mDataDirs); + while (mDataDirs.empty()) { QMessageBox msgBox; msgBox.setWindowTitle("Error detecting Morrowind installation"); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.setText(tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); QAbstractButton *dirSelectButton = - msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); + msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == dirSelectButton) { - QString dataDir = QFileDialog::getExistingDirectory( - this, tr("Select Data Files Directory"), - "/home", - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + // Show a custom dir selection dialog which only accepts valid dirs + QString selectedDir = FileDialog::getExistingDirectory( + this, tr("Select Data Files Directory"), + QDir::currentPath(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + // Add the user selected data directory + if (!selectedDir.isEmpty()) { + mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); + mCfgMgr.processPaths(mDataDirs); + } else { + // Cancel from within the dir selection dialog + break; + } - dataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString())); - mDataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString())); } else { // Cancel break; @@ -249,13 +255,13 @@ void DataFilesPage::setupDataFiles() } // Check if cancel was clicked because we can't exit from while loop - if (dataDirs.empty()) { + if (mDataDirs.empty()) { QApplication::exit(1); return; } - // Create a file collection for the dataDirs - Files::Collections fileCollections(dataDirs, !variables["fs-strict"].as()); + // Create a file collection for the data dirs + Files::Collections fileCollections(mDataDirs, !variables["fs-strict"].as()); // First we add all the master files const Files::MultiDirCollection &esm = fileCollections.getCollection(".esm"); diff --git a/apps/launcher/filedialog.cpp b/apps/launcher/filedialog.cpp new file mode 100644 index 0000000000..20ec3e234f --- /dev/null +++ b/apps/launcher/filedialog.cpp @@ -0,0 +1,57 @@ +#include "filedialog.hpp" +#include +#include + +FileDialog::FileDialog(QWidget *parent) + : QFileDialog(parent) +{ + // Remove the default Choose button to prevent it being updated elsewhere + QDialogButtonBox *box = qFindChild(this); + Q_ASSERT(box); + box->removeButton(box->button(QDialogButtonBox::Open)); + + // Add our own button so we can disable/enable it + mChooseButton = new QPushButton(tr("&Choose")); + mChooseButton->setIcon(QIcon::fromTheme("document-open")); + mChooseButton->setEnabled(false); + box->addButton(mChooseButton, QDialogButtonBox::AcceptRole); + + connect(this, SIGNAL(directoryEntered(const QString&)), this, SLOT(updateChooseButton(const QString&))); + emit directoryEntered(directory().absolutePath()); +} + +QString FileDialog::getExistingDirectory(QWidget *parent, + const QString &caption, + const QString &dir, + Options options) +{ + // create a non-native file dialog + FileDialog dialog; + dialog.setFileMode(DirectoryOnly); + dialog.setOptions(options & DontUseNativeDialog | ShowDirsOnly); + + if (!caption.isEmpty()) + dialog.setWindowTitle(caption); + + if (!dir.isEmpty()) + dialog.setDirectory(dir); + + if (dialog.exec() == QDialog::Accepted) { + return dialog.selectedFiles().value(0); + } + return QString(); +} + +void FileDialog::updateChooseButton(const QString &directory) +{ + QDir currentDir = QDir(directory); + currentDir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); + currentDir.setNameFilters(QStringList() << "*.esm" << "*.esp"); + + if (!currentDir.entryList().isEmpty()) { + // There are data files in the current dir + mChooseButton->setEnabled(true); + } else { + mChooseButton->setEnabled(false); + } +} diff --git a/apps/launcher/filedialog.hpp b/apps/launcher/filedialog.hpp new file mode 100644 index 0000000000..ededcbf39c --- /dev/null +++ b/apps/launcher/filedialog.hpp @@ -0,0 +1,50 @@ +#ifndef FILEDIALOG_HPP +#define FILEDIALOG_HPP + +#include + +class QPushButton; + +struct FileDialogArgs +{ + FileDialogArgs() : parent(0), mode(QFileDialog::AnyFile) {} + QWidget *parent; + QString caption; + QString directory; + QString selection; + QString filter; + QFileDialog::FileMode mode; + QFileDialog::Options options; + +}; + +class FileDialog : public QFileDialog +{ + Q_OBJECT + +public: + FileDialog(QWidget *parent = 0); +// FileDialog(QWidget *parent, Qt::WindowFlags f); + + //QString getExistingDirectory(); + static QString getExistingDirectory(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + Options options = ShowDirsOnly); + //FileDialog mDirectoryDialog; + + bool initialized; +protected: + +private slots: +// void updateOkButton(const QString &text); + void updateChooseButton(const QString &directory); + //void + +private: + QPushButton *mChooseButton; + //QFileDialog *mDirectoryDialog; +}; + + +#endif // FILEDIALOG_HPP diff --git a/apps/launcher/lineedit.cpp b/apps/launcher/lineedit.cpp index 254c09fce3..dac1964258 100644 --- a/apps/launcher/lineedit.cpp +++ b/apps/launcher/lineedit.cpp @@ -1,12 +1,3 @@ -/**************************************************************************** -** -** Copyright (c) 2007 Trolltech ASA -** -** Use, modification and distribution is allowed without limitation, -** warranty, liability or support of any kind. -** -****************************************************************************/ - #include "lineedit.hpp" #include #include @@ -14,33 +5,33 @@ LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) { - clearButton = new QToolButton(this); + mClearButton = new QToolButton(this); QPixmap pixmap(":images/clear.png"); - clearButton->setIcon(QIcon(pixmap)); - clearButton->setIconSize(pixmap.size()); - clearButton->setCursor(Qt::ArrowCursor); - clearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }"); - clearButton->hide(); - connect(clearButton, SIGNAL(clicked()), this, SLOT(clear())); + mClearButton->setIcon(QIcon(pixmap)); + mClearButton->setIconSize(pixmap.size()); + mClearButton->setCursor(Qt::ArrowCursor); + mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }"); + mClearButton->hide(); + connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear())); connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateCloseButton(const QString&))); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); - setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(clearButton->sizeHint().width() + frameWidth + 1)); + setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); QSize msz = minimumSizeHint(); - setMinimumSize(qMax(msz.width(), clearButton->sizeHint().height() + frameWidth * 2 + 2), - qMax(msz.height(), clearButton->sizeHint().height() + frameWidth * 2 + 2)); + setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2), + qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2)); } void LineEdit::resizeEvent(QResizeEvent *) { - QSize sz = clearButton->sizeHint(); + QSize sz = mClearButton->sizeHint(); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); - clearButton->move(rect().right() - frameWidth - sz.width(), + mClearButton->move(rect().right() - frameWidth - sz.width(), (rect().bottom() + 1 - sz.height())/2); } void LineEdit::updateCloseButton(const QString& text) { - clearButton->setVisible(!text.isEmpty()); + mClearButton->setVisible(!text.isEmpty()); } diff --git a/apps/launcher/lineedit.hpp b/apps/launcher/lineedit.hpp index 7a96a523c8..2ed76d6eb7 100644 --- a/apps/launcher/lineedit.hpp +++ b/apps/launcher/lineedit.hpp @@ -28,7 +28,7 @@ private slots: void updateCloseButton(const QString &text); private: - QToolButton *clearButton; + QToolButton *mClearButton; }; #endif // LIENEDIT_H From de3daf3dc15fef32c45805c6aa81ed2f2b773512 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 Jun 2012 00:21:55 +0200 Subject: [PATCH 28/38] allow the 'lock' and 'unlock' script commands to work on containers, like in morrowind --- apps/openmw/mwclass/container.cpp | 13 +++++++++++++ apps/openmw/mwclass/container.hpp | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index e9b8ce31fc..99a32fc327 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -192,4 +192,17 @@ namespace MWClass { return getContainerStore (ptr).getWeight(); } + + void Container::lock (const MWWorld::Ptr& ptr, int lockLevel) const + { + if (lockLevel<0) + lockLevel = 0; + + ptr.getCellRef().lockLevel = lockLevel; + } + + void Container::unlock (const MWWorld::Ptr& ptr) const + { + ptr.getCellRef().lockLevel = 0; + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 44f0fe927b..739c75c77c 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -44,6 +44,12 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; + ///< Lock object + + virtual void unlock (const MWWorld::Ptr& ptr) const; + ///< Unlock object + static void registerSelf(); }; } From 50d81e99fbc474a24a9b3621cc5c6cf136ed0ac2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jun 2012 14:55:22 +0200 Subject: [PATCH 29/38] possible fix for script execution bug --- components/compiler/exprparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 8041a7c8af..52192625b1 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -309,7 +309,7 @@ namespace Compiler if (mExplicit.empty() && getContext().isId (name2)) { - mExplicit = name; + mExplicit = name2; return true; } } From 0aa01b93e298261ef6f4fbe8d459c2d6cd6ec4b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jun 2012 15:24:52 +0200 Subject: [PATCH 30/38] don't put blue color on actions that are in the topic list, but are not topics (e.g. Barter) --- apps/openmw/mwgui/dialogue.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 79b2d68bab..55bd49bebc 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -205,11 +205,14 @@ void addColorInString(std::string& str, const std::string& keyword,std::string c std::string DialogueWindow::parseText(std::string text) { + bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = topicsList->getItemNameAt(i); - if (keyWord != "") + if (separatorReached && keyWord != "") addColorInString(text,keyWord,"#686EBA","#B29154"); + else + separatorReached = true; } return text; } From ff278ab4ec2b1600966937f9c7de823afb8e3b77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jun 2012 15:25:04 +0200 Subject: [PATCH 31/38] chargen generate class: fix result not being shown in review dialog --- apps/openmw/mwgui/charactercreation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 3f9a94e2db..c39e305dc9 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -708,6 +708,9 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) if (mGenerateClassResultDialog) mWM->removeDialog(mGenerateClassResultDialog); MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); + const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().classes.find(mGenerateClass); + mPlayerClass = *klass; + mWM->setPlayerClass(mPlayerClass); if (mCreationStage == CSE_ReviewNext) { From c9e76d3e90d9e09c39721340eb786e148a9c7e0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jun 2012 15:57:58 +0200 Subject: [PATCH 32/38] remove extra tokens at the end of the resolution string, if present --- apps/launcher/graphicspage.cpp | 43 ++++++++++++++++++++++++++++++---- apps/launcher/graphicspage.hpp | 1 + 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index e6940164ea..345b51a114 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -202,11 +202,11 @@ void GraphicsPage::writeConfig() Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString()); Settings::Manager::setString("render system", "Video", mRendererComboBox->currentText().toStdString()); - std::string resolution = mResolutionComboBox->currentText().toStdString(); // parse resolution x and y from a string like "800 x 600" - size_t xPos = resolution.find("x"); - int resX = boost::lexical_cast(resolution.substr(0, xPos-1)); - int resY = boost::lexical_cast(resolution.substr(xPos+2, resolution.size()-(xPos+2))); + QString resolution = mResolutionComboBox->currentText(); + QStringList tokens = resolution.split(" ", QString::SkipEmptyParts); + int resX = boost::lexical_cast(tokens.at(0).toStdString()); + int resY = boost::lexical_cast(tokens.at(2).toStdString()); Settings::Manager::setInt("resolution x", "Video", resX); Settings::Manager::setInt("resolution y", "Video", resY); } @@ -240,6 +240,39 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy return result; } +QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) +{ + QString key ("Video Mode"); + QStringList result; + + uint row = 0; + Ogre::ConfigOptionMap options = renderer->getConfigOptions(); + + for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++) + { + if (key.toStdString() != i->first) + continue; + + Ogre::StringVector::iterator opt_it; + uint idx = 0; + for (opt_it = i->second.possibleValues.begin (); + opt_it != i->second.possibleValues.end (); opt_it++, idx++) + { + QString qval = QString::fromStdString(*opt_it).simplified(); + // remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) + QStringList tokens = qval.split(" ", QString::SkipEmptyParts); + assert (tokens.size() >= 3); + QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); + { + result << resolutionStr; + } + } + + } + + return result; +} + void GraphicsPage::rendererChanged(const QString &renderer) { mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); @@ -248,5 +281,5 @@ void GraphicsPage::rendererChanged(const QString &renderer) mResolutionComboBox->clear(); mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - mResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mSelectedRenderSystem)); + mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); } diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 1b0c6f388c..c2701f3625 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -59,6 +59,7 @@ private: Files::ConfigurationManager &mCfgMgr; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); + QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); void createPages(); void setupConfig(); From 61ec56debc5fa63e26f301caa40870ec5cf469bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jun 2012 16:02:28 +0200 Subject: [PATCH 33/38] don't add duplicate resolutions --- apps/launcher/graphicspage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 345b51a114..22a9ca5bec 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -264,7 +264,10 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) assert (tokens.size() >= 3); QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); { - result << resolutionStr; + + // do not add duplicate resolutions + if (!result.contains(resolutionStr)) + result << resolutionStr; } } From 590dfe8d63e6eb6b608e12177a6dd43918244eea Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jun 2012 16:42:10 +0200 Subject: [PATCH 34/38] fixed the container fill problem on cell load --- apps/openmw/mwworld/cells.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b6d3e38ce7..990a4cc4a3 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -142,7 +142,10 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce (int(*)(int)) std::tolower); if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), lowerCase)) + { cell.load (mStore, mReader); + fillContainers (cell); + } else return Ptr(); } From 15e959868c4d18ce4ab98cc551e7c02adff203c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Jun 2012 17:07:00 +0200 Subject: [PATCH 35/38] make some of the gui mode changes a bit safer --- apps/openmw/mwdialogue/dialoguemanager.cpp | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 4 ++-- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/messagebox.cpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 ++-- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 4 ++-- apps/openmw/mwgui/window_manager.cpp | 5 ++++- apps/openmw/mwworld/actionalchemy.cpp | 1 - 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index a19356d07f..45e2c8cb36 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -843,7 +843,7 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); } void DialogueManager::questionAnswered(std::string answere) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 9c26bfabe4..423678eed0 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -70,8 +70,8 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.popGuiMode(); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Alchemy); + mWindowManager.removeGuiMode(GM_Inventory); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index f1873b5508..a9dcd4555e 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -92,7 +92,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -102,7 +102,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mBook); take.execute(); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Book); } void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6775fa6439..36ed16b0ef 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -640,7 +640,7 @@ void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } } @@ -671,7 +671,7 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) containerStore.clear(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 27e14ba82b..ca04af8303 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -58,7 +58,7 @@ void MessageBoxManager::onFrame (float frameDuration) if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { delete mInterMessageBoxe; mInterMessageBoxe = NULL; - mWindowManager->popGuiMode(); + mWindowManager->removeGuiMode(GM_InterMessageBox); } } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index f4d45fc265..92b18d953d 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -56,7 +56,7 @@ void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -66,5 +66,5 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute(); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 67ccf9d531..eafbd3462a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -155,7 +155,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 47d299fdc6..a42da60d19 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -212,7 +212,7 @@ namespace MWGui std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Barter); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) @@ -222,7 +222,7 @@ namespace MWGui // now gimme back my stuff! mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); - mWindowManager.popGuiMode(); + mWindowManager.removeGuiMode(GM_Barter); } void TradeWindow::updateLabels() diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 5b963d3ae1..f62a3fa0f8 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -464,7 +464,7 @@ void WindowManager::onDialogueWindowBye() //removeDialog(dialogueWindow); mDialogueWindow->setVisible(false); } - popGuiMode(); + removeGuiMode(GM_Dialogue); } void WindowManager::onFrame (float frameDuration) @@ -677,6 +677,9 @@ void WindowManager::removeGuiMode(GuiMode mode) ++it; } + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + updateVisible(); } diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index a2f3bd1e4e..eb91b6946d 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -7,7 +7,6 @@ namespace MWWorld { void ActionAlchemy::execute() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); } } From e21442f6cc67b3830e3465b133c11d4a37d985e4 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 20 Jun 2012 02:28:49 +0200 Subject: [PATCH 36/38] Fix for Bug #306: launcher now creates the config dir and returns proper error codes --- apps/launcher/datafilespage.cpp | 18 +++++++++++++++++- apps/launcher/filedialog.cpp | 2 +- apps/launcher/main.cpp | 6 ++++-- apps/launcher/maindialog.cpp | 12 +++++++----- apps/launcher/maindialog.hpp | 4 ++-- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index a4992bc630..3128c7b759 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -1063,8 +1063,24 @@ void DataFilesPage::writeConfig(QString profile) return; } + QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); + QDir userPath(pathStr); + + if (!userPath.exists()) { + if (!userPath.mkpath(pathStr)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not create %0

\Please make sure you have the right permissions and try again.
").arg(pathStr)); + msgBox.exec(); + + qApp->exit(1); + return; + } + } // Open the OpenMW config as a QFile - QFile file(QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string())); + QFile file(pathStr.append("openmw.cfg")); if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created diff --git a/apps/launcher/filedialog.cpp b/apps/launcher/filedialog.cpp index 20ec3e234f..ead1cbc55b 100644 --- a/apps/launcher/filedialog.cpp +++ b/apps/launcher/filedialog.cpp @@ -17,7 +17,7 @@ FileDialog::FileDialog(QWidget *parent) box->addButton(mChooseButton, QDialogButtonBox::AcceptRole); connect(this, SIGNAL(directoryEntered(const QString&)), this, SLOT(updateChooseButton(const QString&))); - emit directoryEntered(directory().absolutePath()); + emit directoryEntered(QDir::currentPath()); } QString FileDialog::getExistingDirectory(QWidget *parent, diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index bd29e2bcac..cbc1c4da36 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -31,8 +31,10 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - MainDialog dialog; - return dialog.exec(); + MainDialog mainWin; + mainWin.show(); + + return app.exec(); } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index d404fed8e7..63ea96b6f7 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -29,7 +29,10 @@ MainDialog::MainDialog() mSettings.loadUser(globaldefault); - mIconWidget = new QListWidget; + QWidget *centralWidget = new QWidget(this); + setCentralWidget(centralWidget); + + mIconWidget = new QListWidget(centralWidget); mIconWidget->setObjectName("IconWidget"); mIconWidget->setViewMode(QListView::IconMode); mIconWidget->setWrapping(false); @@ -43,7 +46,7 @@ MainDialog::MainDialog() mIconWidget->setCurrentRow(0); mIconWidget->setFlow(QListView::LeftToRight); - QGroupBox *groupBox = new QGroupBox(this); + QGroupBox *groupBox = new QGroupBox(centralWidget); QVBoxLayout *groupLayout = new QVBoxLayout(groupBox); mPagesWidget = new QStackedWidget(groupBox); @@ -51,16 +54,15 @@ MainDialog::MainDialog() QPushButton *playButton = new QPushButton(tr("Play")); - QDialogButtonBox *buttonBox = new QDialogButtonBox(this); + QDialogButtonBox *buttonBox = new QDialogButtonBox(centralWidget); buttonBox->setStandardButtons(QDialogButtonBox::Close); buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole); - QVBoxLayout *dialogLayout = new QVBoxLayout(this); + QVBoxLayout *dialogLayout = new QVBoxLayout(centralWidget); dialogLayout->addWidget(mIconWidget); dialogLayout->addWidget(groupBox); dialogLayout->addWidget(buttonBox); - setWindowTitle(tr("OpenMW Launcher")); setWindowIcon(QIcon(":/images/openmw.png")); // Remove what's this? button diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 0065aa8c47..59c6cbd2d4 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -1,7 +1,7 @@ #ifndef MAINDIALOG_H #define MAINDIALOG_H -#include +#include #include #include @@ -17,7 +17,7 @@ class PlayPage; class GraphicsPage; class DataFilesPage; -class MainDialog : public QDialog +class MainDialog : public QMainWindow { Q_OBJECT From d162445e6868f5e3d5c6a31d9c51d7143c4747cc Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 20 Jun 2012 13:35:05 +0200 Subject: [PATCH 37/38] Got rid of some unwanted warnings and did some cleanup on the launcher --- apps/launcher/datafilespage.cpp | 7 ++++--- apps/launcher/filedialog.cpp | 2 +- apps/launcher/filedialog.hpp | 22 ---------------------- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 3128c7b759..f3c5962cab 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -1072,7 +1072,8 @@ void DataFilesPage::writeConfig(QString profile) msgBox.setWindowTitle("Error creating OpenMW configuration directory"); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not create %0

\Please make sure you have the right permissions and try again.
").arg(pathStr)); + msgBox.setText(tr("
Could not create %0

\ + Please make sure you have the right permissions and try again.
").arg(pathStr)); msgBox.exec(); qApp->exit(1); @@ -1089,7 +1090,7 @@ void DataFilesPage::writeConfig(QString profile) msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); + Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); qApp->exit(1); @@ -1120,7 +1121,7 @@ void DataFilesPage::writeConfig(QString profile) msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not write to %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); + Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); qApp->exit(1); diff --git a/apps/launcher/filedialog.cpp b/apps/launcher/filedialog.cpp index ead1cbc55b..595501b919 100644 --- a/apps/launcher/filedialog.cpp +++ b/apps/launcher/filedialog.cpp @@ -28,7 +28,7 @@ QString FileDialog::getExistingDirectory(QWidget *parent, // create a non-native file dialog FileDialog dialog; dialog.setFileMode(DirectoryOnly); - dialog.setOptions(options & DontUseNativeDialog | ShowDirsOnly); + dialog.setOptions(options & (DontUseNativeDialog | ShowDirsOnly)); if (!caption.isEmpty()) dialog.setWindowTitle(caption); diff --git a/apps/launcher/filedialog.hpp b/apps/launcher/filedialog.hpp index ededcbf39c..7a161ecb96 100644 --- a/apps/launcher/filedialog.hpp +++ b/apps/launcher/filedialog.hpp @@ -5,45 +5,23 @@ class QPushButton; -struct FileDialogArgs -{ - FileDialogArgs() : parent(0), mode(QFileDialog::AnyFile) {} - QWidget *parent; - QString caption; - QString directory; - QString selection; - QString filter; - QFileDialog::FileMode mode; - QFileDialog::Options options; - -}; - class FileDialog : public QFileDialog { Q_OBJECT public: FileDialog(QWidget *parent = 0); -// FileDialog(QWidget *parent, Qt::WindowFlags f); - //QString getExistingDirectory(); static QString getExistingDirectory(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), Options options = ShowDirsOnly); - //FileDialog mDirectoryDialog; - - bool initialized; -protected: private slots: -// void updateOkButton(const QString &text); void updateChooseButton(const QString &directory); - //void private: QPushButton *mChooseButton; - //QFileDialog *mDirectoryDialog; }; From 01d1995164c18033d785662ba7d53fbd3275a4a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Jun 2012 18:22:18 +0200 Subject: [PATCH 38/38] fix compilation against latest bullet svn --- libs/openengine/bullet/physic.cpp | 16 ++++++++-------- libs/openengine/bullet/physic.hpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f7caa54b49..1bc4341a09 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -488,7 +488,7 @@ namespace Physic dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit()) { - name = static_cast(*resultCallback1.m_collisionObject).mName; + name = static_cast(*resultCallback1.m_collisionObject).mName; d1 = resultCallback1.m_closestHitFraction; d = d1; } @@ -502,7 +502,7 @@ namespace Physic d2 = resultCallback1.m_closestHitFraction; if(d2<=d1) { - name = static_cast(*resultCallback2.m_collisionObject).mName; + name = static_cast(*resultCallback2.m_collisionObject).mName; d = d2; } } @@ -515,25 +515,25 @@ namespace Physic MyRayResultCallback resultCallback1; resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; dynamicsWorld->rayTest(from, to, resultCallback1); - std::vector< std::pair > results = resultCallback1.results; + std::vector< std::pair > results = resultCallback1.results; MyRayResultCallback resultCallback2; resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL; dynamicsWorld->rayTest(from, to, resultCallback2); - std::vector< std::pair > actorResults = resultCallback2.results; + std::vector< std::pair > actorResults = resultCallback2.results; std::vector< std::pair > results2; - for (std::vector< std::pair >::iterator it=results.begin(); + for (std::vector< std::pair >::iterator it=results.begin(); it != results.end(); ++it) { - results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); + results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); } - for (std::vector< std::pair >::iterator it=actorResults.begin(); + for (std::vector< std::pair >::iterator it=actorResults.begin(); it != actorResults.end(); ++it) { - results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); + results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); } std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 8115723201..e327f24e15 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -278,7 +278,7 @@ namespace Physic return false; } - std::vector < std::pair > results; + std::vector < std::pair > results; }; }}