diff --git a/.gitignore b/.gitignore index 9f2cba3bf..f22f1bd49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,53 @@ -build -*~ -Doxygen -prebuilt -apps/openmw/config.hpp -Docs/mainpage.hpp +## make CMakeFiles */CMakeFiles CMakeCache.txt -moc_*.cxx cmake_install.cmake -*.[ao] +CMakeLists.txt.user Makefile makefile -data +build +prebuilt + +## doxygen +Doxygen + +## ides/editors +*~ *.kdev4 -CMakeLists.txt.user *.swp *.swo *.kate-swp .cproject .project -.settings/ +.settings .directory + +## resources +data +resources +/*.cfg +/*.desktop +/*.install + +## binaries +/esmtool +/mwiniimport +/omwlauncher +/openmw +/opencs + +## generated objects +apps/openmw/config.hpp +Docs/mainpage.hpp +moc_*.cxx +*.cxx_parameters +*qrc_launcher.cxx +*qrc_resources.cxx +*__* +*ui_datafilespage.h +*ui_graphicspage.h +*ui_mainwindow.h +*ui_playpage.h +*.[ao] +*.so diff --git a/apps/launcher/unshieldthread.cpp b/apps/launcher/unshieldthread.cpp index 6ddad7a21..69b241365 100644 --- a/apps/launcher/unshieldthread.cpp +++ b/apps/launcher/unshieldthread.cpp @@ -77,6 +77,8 @@ namespace ini.insert(loc, setting + "=" + val + "\r\n"); } + #define FIX(setting) add_setting(category, setting, get_setting(category, setting, inx), ini) + void bloodmoon_fix_ini(std::string& ini, const bfs::path inxPath) { std::string inx = read_to_string(inxPath); @@ -88,95 +90,94 @@ namespace ini.erase(start, end-start); std::string category; - std::string setting; category = "General"; { - setting = "Werewolf FOV"; add_setting(category, setting, get_setting(category, setting, inx), ini); + FIX("Werewolf FOV"); } category = "Moons"; { - setting = "Script Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); + FIX("Script Color"); } category = "Weather"; { - setting = "Snow Ripples"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Ripple Radius"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Ripples Per Flake"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Ripple Scale"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Ripple Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Gravity Scale"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow High Kill"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Low Kill"; add_setting(category, setting, get_setting(category, setting, inx), ini); + FIX("Snow Ripples"); + FIX("Snow Ripple Radius"); + FIX("Snow Ripples Per Flake"); + FIX("Snow Ripple Scale"); + FIX("Snow Ripple Speed"); + FIX("Snow Gravity Scale"); + FIX("Snow High Kill"); + FIX("Snow Low Kill"); } category = "Weather Blight"; { - setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini); + FIX("Ambient Loop Sound ID"); } category = "Weather Snow"; { - setting = "Sky Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sky Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sky Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sky Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Disc Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Transition Delta"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Land Fog Day Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Land Fog Night Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Clouds Maximum Percent"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Wind Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Cloud Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Glare View"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Cloud Texture"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Threshold"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Diameter"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Height Min"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Height Max"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Snow Entrance Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Max Snowflakes"; add_setting(category, setting, get_setting(category, setting, inx), ini); + FIX("Sky Sunrise Color"); + FIX("Sky Day Color"); + FIX("Sky Sunset Color"); + FIX("Sky Night Color"); + FIX("Fog Sunrise Color"); + FIX("Fog Day Color"); + FIX("Fog Sunset Color"); + FIX("Fog Night Color"); + FIX("Ambient Sunrise Color"); + FIX("Ambient Day Color"); + FIX("Ambient Sunset Color"); + FIX("Ambient Night Color"); + FIX("Sun Sunrise Color"); + FIX("Sun Day Color"); + FIX("Sun Sunset Color"); + FIX("Sun Night Color"); + FIX("Sun Disc Sunset Color"); + FIX("Transition Delta"); + FIX("Land Fog Day Depth"); + FIX("Land Fog Night Depth"); + FIX("Clouds Maximum Percent"); + FIX("Wind Speed"); + FIX("Cloud Speed"); + FIX("Glare View"); + FIX("Cloud Texture"); + FIX("Ambient Loop Sound ID"); + FIX("Snow Threshold"); + FIX("Snow Diameter"); + FIX("Snow Height Min"); + FIX("Snow Height Max"); + FIX("Snow Entrance Speed"); + FIX("Max Snowflakes"); } category = "Weather Blizzard"; { - setting = "Sky Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sky Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sky Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sky Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Fog Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Sun Disc Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Transition Delta"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Land Fog Day Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Land Fog Night Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Clouds Maximum Percent"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Wind Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Cloud Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Glare View"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Cloud Texture"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini); - setting = "Storm Threshold"; add_setting(category, setting, get_setting(category, setting, inx), ini); + FIX("Sky Sunrise Color"); + FIX("Sky Day Color"); + FIX("Sky Sunset Color"); + FIX("Sky Night Color"); + FIX("Fog Sunrise Color"); + FIX("Fog Day Color"); + FIX("Fog Sunset Color"); + FIX("Fog Night Color"); + FIX("Ambient Sunrise Color"); + FIX("Ambient Day Color"); + FIX("Ambient Sunset Color"); + FIX("Ambient Night Color"); + FIX("Sun Sunrise Color"); + FIX("Sun Day Color"); + FIX("Sun Sunset Color"); + FIX("Sun Night Color"); + FIX("Sun Disc Sunset Color"); + FIX("Transition Delta"); + FIX("Land Fog Day Depth"); + FIX("Land Fog Night Depth"); + FIX("Clouds Maximum Percent"); + FIX("Wind Speed"); + FIX("Cloud Speed"); + FIX("Glare View"); + FIX("Cloud Texture"); + FIX("Ambient Loop Sound ID"); + FIX("Storm Threshold"); } } @@ -268,6 +269,27 @@ namespace strptime(time, "%d %B %Y", &tms); return mktime(&tms); } + + // Some cds have cab files which have the Data Files subfolders outside the Data Files folder + void install_dfiles_outside(const bfs::path& from, const bfs::path& dFiles) + { + bfs::path fonts = findFile(from, "fonts", false); + if(fonts.string() != "") + installToPath(fonts, dFiles / "Fonts"); + + bfs::path music = findFile(from, "music", false); + if(music.string() != "") + installToPath(music, dFiles / "Music"); + + bfs::path sound = findFile(from, "sound", false); + if(sound.string() != "") + installToPath(sound, dFiles / "Sound"); + + bfs::path splash = findFile(from, "splash", false); + if(splash.string() != "") + installToPath(splash, dFiles / "Splash"); + } + } bool UnshieldThread::SetMorrowindPath(const std::string& path) @@ -365,6 +387,8 @@ bool UnshieldThread::extract() installToPath(dFilesDir, outputDataFilesDir); + install_dfiles_outside(mwExtractPath, outputDataFilesDir); + // Videos are often kept uncompressed on the cd bfs::path videosPath = findFile(mMorrowindPath.parent_path(), "video", false); if(videosPath.string() != "") @@ -399,6 +423,8 @@ bool UnshieldThread::extract() installToPath(dFilesDir, outputDataFilesDir); + install_dfiles_outside(tbExtractPath, outputDataFilesDir); + // Mt GOTY CD has Sounds in a seperate folder from the rest of the data files bfs::path soundsPath = findFile(tbExtractPath, "sounds", false); if(soundsPath.string() != "") @@ -426,6 +452,8 @@ bool UnshieldThread::extract() bfs::path dFilesDir = findFile(bmExtractPath, "bloodmoon.esm").parent_path(); installToPath(dFilesDir, outputDataFilesDir); + + install_dfiles_outside(bmExtractPath, outputDataFilesDir); // My GOTY CD contains a folder within cab files called Tribunal patch, // which contains Tribunal.esm diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bc78352d4..2d6490bd4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -59,7 +59,8 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator - cellcreator referenceablecreator referencecreator + cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool + scenetoolmode ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index f3d98ce53..7d1a4845f 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -34,7 +34,7 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, { string = data.toString(); } - else if (data.type()==QVariant::Int || data.type()==QVariant::UInt || + else if ((data.type()==QVariant::Int || data.type()==QVariant::UInt) && CSMWorld::Columns::hasEnums (static_cast (mColumnId))) { int value = data.toInt(); @@ -47,8 +47,10 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, } else if (data.type()==QVariant::Bool) { - string = data.toBool() ? "true" : " false"; + string = data.toBool() ? "true" : "false"; } + else if (mText.empty() && !data.isValid()) + return true; else return false; diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 7eeb6beab..fdcce00ab 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -17,7 +17,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, const std::map::const_iterator iter = columns.find (mColumnId); if (iter==columns.end()) - throw std::logic_error ("invalid column in test value test"); + throw std::logic_error ("invalid column in value node test"); if (iter->second==-1) return true; @@ -27,7 +27,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, QVariant data = table.data (index); if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int && - data.type()!=QVariant::UInt) + data.type()!=QVariant::UInt && data.type()!=static_cast (QMetaType::Float)) return false; double value = data.toDouble(); @@ -68,7 +68,7 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const << CSMWorld::Columns::getName (static_cast (mColumnId)) << "\""; - stream << ", \""; + stream << ", "; if (mLower==mUpper && mLowerType!=Type_Infinite && mUpperType!=Type_Infinite) stream << mLower; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 25047807a..ca37840ad 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -51,7 +51,7 @@ namespace CSMWorld { ColumnId_FactionIndex, "Faction Index" }, { ColumnId_Charges, "Charges" }, { ColumnId_Enchantment, "Enchantment" }, - { ColumnId_Value, "Coin Value" }, + { ColumnId_CoinValue, "Coin Value" }, { ColumnId_Teleport, "Teleport" }, { ColumnId_TeleportCell, "Teleport Cell" }, { ColumnId_LockLevel, "Lock Level" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 582f5102b..9b26cac4c 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -45,113 +45,113 @@ namespace CSMWorld ColumnId_Charges = 32, ColumnId_Enchantment = 33, ColumnId_CoinValue = 34, - ColumnId_Teleport = 25, - ColumnId_TeleportCell = 26, - ColumnId_LockLevel = 27, - ColumnId_Key = 28, - ColumnId_Trap = 29, - ColumnId_BeastRace = 30, - ColumnId_AutoCalc = 31, - ColumnId_StarterSpell = 32, - ColumnId_AlwaysSucceeds = 33, - ColumnId_SleepForbidden = 34, - ColumnId_InteriorWater = 35, - ColumnId_InteriorSky = 36, - ColumnId_Model = 37, - ColumnId_Script = 38, - ColumnId_Icon = 39, - ColumnId_Weight = 40, - ColumnId_EnchantmentPoints = 31, - ColumnId_Quality = 32, - ColumnId_Ai = 33, - ColumnId_AiHello = 34, - ColumnId_AiFlee = 35, - ColumnId_AiFight = 36, - ColumnId_AiAlarm = 37, - ColumnId_BuysWeapons = 38, - ColumnId_BuysArmor = 39, - ColumnId_BuysClothing = 40, - ColumnId_BuysBooks = 41, - ColumnId_BuysIngredients = 42, - ColumnId_BuysLockpicks = 43, - ColumnId_BuysProbes = 44, - ColumnId_BuysLights = 45, - ColumnId_BuysApparati = 46, - ColumnId_BuysRepairItems = 47, - ColumnId_BuysMiscItems = 48, - ColumnId_BuysPotions = 49, - ColumnId_BuysMagicItems = 50, - ColumnId_SellsSpells = 51, - ColumnId_Trainer = 52, - ColumnId_Spellmaking = 53, - ColumnId_EnchantingService = 54, - ColumnId_RepairService = 55, - ColumnId_ApparatusType = 56, - ColumnId_ArmorType = 57, - ColumnId_Health = 58, - ColumnId_ArmorValue = 59, - ColumnId_Scroll = 60, - ColumnId_ClothingType = 61, - ColumnId_WeightCapacity = 62, - ColumnId_OrganicContainer = 63, - ColumnId_Respawn = 64, - ColumnId_CreatureType = 65, - ColumnId_SoulPoints = 66, - ColumnId_OriginalCreature = 67, - ColumnId_Biped = 68, - ColumnId_HasWeapon = 69, - ColumnId_NoMovement = 70, - ColumnId_Swims = 71, - ColumnId_Flies = 72, - ColumnId_Walks = 73, - ColumnId_Essential = 74, - ColumnId_SkeletonBlood = 75, - ColumnId_MetalBlood = 76, - ColumnId_OpenSound = 77, - ColumnId_CloseSound = 78, - ColumnId_Duration = 79, - ColumnId_Radius = 80, - ColumnId_Colour = 81, - ColumnId_Sound = 82, - ColumnId_Dynamic = 83, - ColumnId_Portable = 84, - ColumnId_NegativeLight = 85, - ColumnId_Flickering = 86, - ColumnId_SlowFlickering = 87, - ColumnId_Pulsing = 88, - ColumnId_SlowPulsing = 89, - ColumnId_Fire = 90, - ColumnId_OffByDefault = 91, - ColumnId_IsKey = 92, - ColumnId_Race = 93, - ColumnId_Class = 94, - Columnid_Hair = 95, - ColumnId_Head = 96, - ColumnId_Female = 97, - ColumnId_WeaponType = 98, - ColumnId_WeaponSpeed = 99, - ColumnId_WeaponReach = 100, - ColumnId_MinChop = 101, - ColumnId_MaxChip = 102, - Columnid_MinSlash = 103, - ColumnId_MaxSlash = 104, - ColumnId_MinThrust = 105, - ColumnId_MaxThrust = 106, - ColumnId_Magical = 107, - ColumnId_Silver = 108, - ColumnId_Filter = 109, - ColumnId_PositionXPos = 110, - ColumnId_PositionYPos = 111, - ColumnId_PositionZPos = 112, - ColumnId_PositionXRot = 113, - ColumnId_PositionYRot = 114, - ColumnId_PositionZRot = 115, - ColumnId_DoorPositionXPos = 116, - ColumnId_DoorPositionYPos = 117, - ColumnId_DoorPositionZPos = 118, - ColumnId_DoorPositionXRot = 119, - ColumnId_DoorPositionYRot = 120, - ColumnId_DoorPositionZRot = 121, + ColumnId_Teleport = 35, + ColumnId_TeleportCell = 36, + ColumnId_LockLevel = 37, + ColumnId_Key = 38, + ColumnId_Trap = 39, + ColumnId_BeastRace = 40, + ColumnId_AutoCalc = 41, + ColumnId_StarterSpell = 42, + ColumnId_AlwaysSucceeds = 43, + ColumnId_SleepForbidden = 44, + ColumnId_InteriorWater = 45, + ColumnId_InteriorSky = 46, + ColumnId_Model = 47, + ColumnId_Script = 48, + ColumnId_Icon = 49, + ColumnId_Weight = 50, + ColumnId_EnchantmentPoints = 51, + ColumnId_Quality = 52, + ColumnId_Ai = 53, + ColumnId_AiHello = 54, + ColumnId_AiFlee = 55, + ColumnId_AiFight = 56, + ColumnId_AiAlarm = 57, + ColumnId_BuysWeapons = 58, + ColumnId_BuysArmor = 59, + ColumnId_BuysClothing = 60, + ColumnId_BuysBooks = 61, + ColumnId_BuysIngredients = 62, + ColumnId_BuysLockpicks = 63, + ColumnId_BuysProbes = 64, + ColumnId_BuysLights = 65, + ColumnId_BuysApparati = 66, + ColumnId_BuysRepairItems = 67, + ColumnId_BuysMiscItems = 68, + ColumnId_BuysPotions = 69, + ColumnId_BuysMagicItems = 70, + ColumnId_SellsSpells = 71, + ColumnId_Trainer = 72, + ColumnId_Spellmaking = 73, + ColumnId_EnchantingService = 74, + ColumnId_RepairService = 75, + ColumnId_ApparatusType = 76, + ColumnId_ArmorType = 77, + ColumnId_Health = 78, + ColumnId_ArmorValue = 79, + ColumnId_Scroll = 80, + ColumnId_ClothingType = 81, + ColumnId_WeightCapacity = 82, + ColumnId_OrganicContainer = 83, + ColumnId_Respawn = 84, + ColumnId_CreatureType = 85, + ColumnId_SoulPoints = 86, + ColumnId_OriginalCreature = 87, + ColumnId_Biped = 88, + ColumnId_HasWeapon = 89, + ColumnId_NoMovement = 90, + ColumnId_Swims = 91, + ColumnId_Flies = 92, + ColumnId_Walks = 93, + ColumnId_Essential = 94, + ColumnId_SkeletonBlood = 95, + ColumnId_MetalBlood = 96, + ColumnId_OpenSound = 97, + ColumnId_CloseSound = 98, + ColumnId_Duration = 99, + ColumnId_Radius = 100, + ColumnId_Colour = 101, + ColumnId_Sound = 102, + ColumnId_Dynamic = 103, + ColumnId_Portable = 104, + ColumnId_NegativeLight = 105, + ColumnId_Flickering = 106, + ColumnId_SlowFlickering = 107, + ColumnId_Pulsing = 108, + ColumnId_SlowPulsing = 109, + ColumnId_Fire = 110, + ColumnId_OffByDefault = 111, + ColumnId_IsKey = 112, + ColumnId_Race = 113, + ColumnId_Class = 114, + Columnid_Hair = 115, + ColumnId_Head = 116, + ColumnId_Female = 117, + ColumnId_WeaponType = 118, + ColumnId_WeaponSpeed = 119, + ColumnId_WeaponReach = 120, + ColumnId_MinChop = 121, + ColumnId_MaxChip = 122, + Columnid_MinSlash = 123, + ColumnId_MaxSlash = 124, + ColumnId_MinThrust = 125, + ColumnId_MaxThrust = 126, + ColumnId_Magical = 127, + ColumnId_Silver = 128, + ColumnId_Filter = 129, + ColumnId_PositionXPos = 130, + ColumnId_PositionYPos = 131, + ColumnId_PositionZPos = 132, + ColumnId_PositionXRot = 133, + ColumnId_PositionYRot = 134, + ColumnId_PositionZRot = 135, + ColumnId_DoorPositionXPos = 136, + ColumnId_DoorPositionYPos = 137, + ColumnId_DoorPositionZPos = 138, + ColumnId_DoorPositionXRot = 139, + ColumnId_DoorPositionYRot = 140, + ColumnId_DoorPositionZRot = 141, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 60a8485f8..c9edd0c16 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -87,6 +87,7 @@ namespace static const TypeData sIndexArg[] = { { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, + { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index aa0cdacc0..246640733 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -86,10 +86,11 @@ namespace CSMWorld Type_Reference, Type_RegionMap, Type_Filter, - Type_Filters + Type_Filters, + Type_Scene }; - enum { NumberOfTypes = Type_Filters+1 }; + enum { NumberOfTypes = Type_Scene+1 }; private: diff --git a/apps/opencs/ocspropertywidget.cpp b/apps/opencs/ocspropertywidget.cpp deleted file mode 100644 index 68315201a..000000000 --- a/apps/opencs/ocspropertywidget.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "ocspropertywidget.hpp" - -OcsPropertyWidget::OcsPropertyWidget(QObject *parent) : - QObject(parent) -{ -} diff --git a/apps/opencs/ocspropertywidget.hpp b/apps/opencs/ocspropertywidget.hpp deleted file mode 100644 index fc64a0a69..000000000 --- a/apps/opencs/ocspropertywidget.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OCSPROPERTYWIDGET_HPP -#define OCSPROPERTYWIDGET_HPP - -#include - -class OcsPropertyWidget : public QObject -{ - Q_OBJECT -public: - explicit OcsPropertyWidget(QObject *parent = 0); - -signals: - -public slots: - -}; - -#endif // OCSPROPERTYWIDGET_HPP diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 2784bca8c..b1eec63c3 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -65,7 +65,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (path.parent_path().string()==mLocalData.string()) { // path already points to the local data directory - message = QString::fromUtf8 (("Will be saved as: " + path.native()).c_str()); + message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); mResultPath = path; mValid = true; } @@ -74,7 +74,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) // path points somewhere else or is a leaf name. path = mLocalData / path.filename(); - message = QString::fromUtf8 (("Will be saved as: " + path.native()).c_str()); + message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); mResultPath = path; mValid = true; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 7183753e1..b29250d20 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -115,6 +115,10 @@ void CSVDoc::View::setupWorldMenu() world->addSeparator(); // items that don't represent single record lists follow here + QAction *scene = new QAction (tr ("Scene"), this); + connect (scene, SIGNAL (triggered()), this, SLOT (addSceneSubView())); + world->addAction (scene); + QAction *regionMap = new QAction (tr ("Region Map"), this); connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView())); world->addAction (regionMap); @@ -403,6 +407,11 @@ void CSVDoc::View::addFiltersSubView() addSubView (CSMWorld::UniversalId::Type_Filters); } +void CSVDoc::View::addSceneSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Scene); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 29a1d52f7..6f3c38daa 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -164,6 +164,8 @@ namespace CSVDoc void addFiltersSubView(); + void addSceneSubView(); + void toggleShowStatusBar (bool show); }; } diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp new file mode 100644 index 000000000..e3618c549 --- /dev/null +++ b/apps/opencs/view/world/scenesubview.cpp @@ -0,0 +1,82 @@ + +#include "scenesubview.hpp" + +#include +#include +#include + +#include "../../model/doc/document.hpp" + +#include "../filter/filterbox.hpp" + +#include "tablebottombox.hpp" +#include "creator.hpp" +#include "scenetoolbar.hpp" +#include "scenetoolmode.hpp" + +CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: SubView (id) +{ + QVBoxLayout *layout = new QVBoxLayout; + + layout->setContentsMargins (QMargins (0, 0, 0, 0)); + + layout->addWidget (mBottom = + new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id, + this), 0); + + QHBoxLayout *layout2 = new QHBoxLayout; + + layout2->setContentsMargins (QMargins (0, 0, 0, 0)); + + SceneToolbar *toolbar = new SceneToolbar (48, this); +// test +SceneToolMode *tool = new SceneToolMode (toolbar); +tool->addButton (":door.png", "a"); +tool->addButton (":GMST.png", "b"); +tool->addButton (":Info.png", "c"); +toolbar->addTool (tool); +toolbar->addTool (new SceneToolMode (toolbar)); +toolbar->addTool (new SceneToolMode (toolbar)); +toolbar->addTool (new SceneToolMode (toolbar)); + layout2->addWidget (toolbar, 0); + + /// \todo replace with rendering widget + QPalette palette2 (palette()); + palette2.setColor (QPalette::Background, Qt::white); + QLabel *placeholder = new QLabel ("Here goes the 3D scene", this); + placeholder->setAutoFillBackground (true); + placeholder->setPalette (palette2); + placeholder->setAlignment (Qt::AlignHCenter); + + layout2->addWidget (placeholder, 1); + + layout->insertLayout (0, layout2, 1); + + CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); + + layout->insertWidget (0, filterBox); + + QWidget *widget = new QWidget; + + widget->setLayout (layout); + + setWidget (widget); +} + +void CSVWorld::SceneSubView::setEditLock (bool locked) +{ + + +} + +void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) +{ + + +} + +void CSVWorld::SceneSubView::setStatusBar (bool show) +{ + mBottom->setStatusBar (show); +} \ No newline at end of file diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp new file mode 100644 index 000000000..a0fed908d --- /dev/null +++ b/apps/opencs/view/world/scenesubview.hpp @@ -0,0 +1,37 @@ +#ifndef CSV_WORLD_SCENESUBVIEW_H +#define CSV_WORLD_SCENESUBVIEW_H + +#include "../doc/subview.hpp" + +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class Table; + class TableBottomBox; + class CreatorFactoryBase; + + class SceneSubView : public CSVDoc::SubView + { + Q_OBJECT + + TableBottomBox *mBottom; + + public: + + SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + virtual void updateEditorSetting (const QString& key, const QString& value); + + virtual void setStatusBar (bool show); + }; +} + +#endif diff --git a/apps/opencs/view/world/scenetool.cpp b/apps/opencs/view/world/scenetool.cpp new file mode 100644 index 000000000..320deb1ba --- /dev/null +++ b/apps/opencs/view/world/scenetool.cpp @@ -0,0 +1,17 @@ + +#include "scenetool.hpp" + +#include "scenetoolbar.hpp" + +CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent) +{ + setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + setFixedSize (parent->getButtonSize(), parent->getButtonSize()); + + connect (this, SIGNAL (clicked()), this, SLOT (openRequest())); +} + +void CSVWorld::SceneTool::openRequest() +{ + showPanel (parentWidget()->mapToGlobal (pos())); +} diff --git a/apps/opencs/view/world/scenetool.hpp b/apps/opencs/view/world/scenetool.hpp new file mode 100644 index 000000000..07e8b58d7 --- /dev/null +++ b/apps/opencs/view/world/scenetool.hpp @@ -0,0 +1,27 @@ +#ifndef CSV_WORLD_SCENETOOL_H +#define CSV_WORLD_SCENETOOL_H + +#include + +namespace CSVWorld +{ + class SceneToolbar; + + ///< \brief Tool base class + class SceneTool : public QPushButton + { + Q_OBJECT + + public: + + SceneTool (SceneToolbar *parent); + + virtual void showPanel (const QPoint& position) = 0; + + private slots: + + void openRequest(); + }; +} + +#endif diff --git a/apps/opencs/view/world/scenetoolbar.cpp b/apps/opencs/view/world/scenetoolbar.cpp new file mode 100644 index 000000000..2972c5391 --- /dev/null +++ b/apps/opencs/view/world/scenetoolbar.cpp @@ -0,0 +1,29 @@ + +#include "scenetoolbar.hpp" + +#include + +#include "scenetool.hpp" + +CSVWorld::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) +: QWidget (parent), mButtonSize (buttonSize) +{ + setFixedWidth (mButtonSize); + + mLayout = new QVBoxLayout (this); + mLayout->setAlignment (Qt::AlignTop); + + mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); + + setLayout (mLayout); +} + +void CSVWorld::SceneToolbar::addTool (SceneTool *tool) +{ + mLayout->addWidget (tool, 0, Qt::AlignTop); +} + +int CSVWorld::SceneToolbar::getButtonSize() const +{ + return mButtonSize; +} \ No newline at end of file diff --git a/apps/opencs/view/world/scenetoolbar.hpp b/apps/opencs/view/world/scenetoolbar.hpp new file mode 100644 index 000000000..f713ca3df --- /dev/null +++ b/apps/opencs/view/world/scenetoolbar.hpp @@ -0,0 +1,29 @@ +#ifndef CSV_WORLD_SCENETOOLBAR_H +#define CSV_WORLD_SCENETOOLBAR_H + +#include + +class QVBoxLayout; + +namespace CSVWorld +{ + class SceneTool; + + class SceneToolbar : public QWidget + { + Q_OBJECT + + QVBoxLayout *mLayout; + int mButtonSize; + + public: + + SceneToolbar (int buttonSize, QWidget *parent = 0); + + void addTool (SceneTool *tool); + + int getButtonSize() const; + }; +} + +#endif diff --git a/apps/opencs/view/world/scenetoolmode.cpp b/apps/opencs/view/world/scenetoolmode.cpp new file mode 100644 index 000000000..281d703b6 --- /dev/null +++ b/apps/opencs/view/world/scenetoolmode.cpp @@ -0,0 +1,56 @@ + +#include "scenetoolmode.hpp" + +#include +#include +#include + +#include "scenetoolbar.hpp" + +CSVWorld::SceneToolMode::SceneToolMode (SceneToolbar *parent) +: SceneTool (parent), mButtonSize (parent->getButtonSize()) +{ + mPanel = new QFrame (this, Qt::Popup); + + mLayout = new QHBoxLayout (mPanel); + + mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); + + mPanel->setLayout (mLayout); +} + +void CSVWorld::SceneToolMode::showPanel (const QPoint& position) +{ + mPanel->move (position); + mPanel->show(); +} + +void CSVWorld::SceneToolMode::addButton (const std::string& icon, const std::string& id) +{ + QPushButton *button = new QPushButton (QIcon (QPixmap (icon.c_str())), "", mPanel); + button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + button->setFixedSize (mButtonSize, mButtonSize); + + mLayout->addWidget (button); + + mButtons.insert (std::make_pair (button, id)); + + connect (button, SIGNAL (clicked()), this, SLOT (selected())); + + if (mButtons.size()==1) + setIcon (button->icon()); +} + +void CSVWorld::SceneToolMode::selected() +{ + std::map::const_iterator iter = + mButtons.find (dynamic_cast (sender())); + + if (iter!=mButtons.end()) + { + mPanel->hide(); + + setIcon (iter->first->icon()); + emit modeChanged (iter->second); + } +} \ No newline at end of file diff --git a/apps/opencs/view/world/scenetoolmode.hpp b/apps/opencs/view/world/scenetoolmode.hpp new file mode 100644 index 000000000..a8fe2b5a6 --- /dev/null +++ b/apps/opencs/view/world/scenetoolmode.hpp @@ -0,0 +1,42 @@ +#ifndef CSV_WORLD_SCENETOOL_MODE_H +#define CSV_WORLD_SCENETOOL_MODE_H + +#include "scenetool.hpp" + +#include + +class QHBoxLayout; + +namespace CSVWorld +{ + class SceneToolbar; + + ///< \brief Mode selector tool + class SceneToolMode : public SceneTool + { + Q_OBJECT + + QWidget *mPanel; + QHBoxLayout *mLayout; + std::map mButtons; // widget, id + int mButtonSize; + + public: + + SceneToolMode (SceneToolbar *parent); + + virtual void showPanel (const QPoint& position); + + void addButton (const std::string& icon, const std::string& id); + + signals: + + void modeChanged (const std::string& id); + + private slots: + + void selected(); + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index d22e07d89..0e3465b38 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -13,6 +13,7 @@ #include "cellcreator.hpp" #include "referenceablecreator.hpp" #include "referencecreator.hpp" +#include "scenesubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -62,4 +63,5 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory); } \ No newline at end of file diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a2eccbaf9..e1fd3a0af 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -399,8 +399,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding); mEnvironment.setWindowManager (window); - if (mNewGame) - mEnvironment.getWindowManager()->setNewGame(true); // Create the world mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, @@ -410,6 +408,10 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); + if (mNewGame) + // still redundant work here: recreate CharacterCreation(), + // double update visibility etc. + window->setNewGame(true); window->renderWorldMap(); //Load translation data diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f8453afed..c39e87826 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -324,6 +324,7 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; + virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; @@ -389,6 +390,12 @@ namespace MWBase /// Returns true if teleport spell effects are allowed. virtual bool isTeleportingEnabled() const = 0; + /// Enables or disables use of levitation spell effect. + virtual void enableLevitation(bool enable) = 0; + + /// Returns true if levitation spell effect is allowed. + virtual bool isLevitationEnabled() const = 0; + /// Turn actor into werewolf or normal form. virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7eefc6167..a593eb295 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -16,12 +16,34 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/customdata.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +namespace +{ + struct CustomData : public MWWorld::CustomData + { + float mTime; + ///< Time remaining + + CustomData(MWWorld::Ptr ptr) + { + MWWorld::LiveCellRef *ref = ptr.get(); + mTime = ref->mBase->mData.mTime; + } + ///< Constructs this CustomData from the base values for Ptr. + + virtual MWWorld::CustomData *clone() const + { + return new CustomData (*this); + } + }; +} + namespace MWClass { void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -182,6 +204,21 @@ namespace MWClass return action; } + void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const + { + ensureCustomData(ptr); + + float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + timeRemaining = duration; + } + + float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const + { + ensureCustomData(ptr); + + return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + } + MWWorld::Ptr Light::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { @@ -191,6 +228,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell); } + void Light::ensureCustomData (const MWWorld::Ptr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + ptr.getRefData().setCustomData(new CustomData(ptr)); + } + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 79d662763..c15228a6a 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,6 +10,8 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + void ensureCustomData (const MWWorld::Ptr& ptr) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -56,6 +58,12 @@ namespace MWClass const; ///< Generate action for using via inventory menu + virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const; + ///< Sets the remaining duration of the object. + + virtual float getRemainingUsageTime (const MWWorld::Ptr& ptr) const; + ///< Returns the remaining duration of the object. + virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 073d1b1b9..01a0c0a6f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -7,6 +7,7 @@ #include +#include #include #include "../mwbase/environment.hpp" @@ -396,9 +397,10 @@ namespace MWClass MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}"); MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); } - weapon.getCellRef().mCharge -= std::min(std::max(1, - (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), - weapon.getCellRef().mCharge); + + if (!MWBase::Environment::get().getWorld()->getGodModeState()) + weapon.getCellRef().mCharge -= std::min(std::max(1, + (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); } healthdmg = true; } @@ -769,6 +771,37 @@ namespace MWClass return x; } + float Npc::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + const float fallDistanceMin = gmst.find("fFallDamageDistanceMin")->getFloat(); + + if (fallHeight >= fallDistanceMin) + { + const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified(); + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude; + const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat(); + const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat(); + const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat(); + const float fallDistanceMult = gmst.find("fFallDistanceMult")->getFloat(); + + float x = fallHeight - fallDistanceMin; + x -= (1.5 * acrobaticsSkill) + jumpSpellBonus; + x = std::max(0.0f, x); + + float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill); + x = fallDistanceBase + fallDistanceMult * x; + x *= a; + + return x; + } + + return 0; + } + MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 3591d7c68..c39ca42ef 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -97,6 +97,9 @@ namespace MWClass virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) + virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const; + ///< Return amount of health points lost when falling + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9b63dfa76..4bd383c2f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -23,6 +23,7 @@ namespace MWGui , mLastWallpaperChangeTime(0.f) , mFirstLoad(true) , mProgress(0) + , mVSyncWasEnabled(false) { getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); @@ -67,6 +68,14 @@ namespace MWGui void LoadingScreen::loadingOn() { + // Temporarily turn off VSync, we want to do actual loading rather than waiting for the screen to sync. + // Threaded loading would be even better, of course - especially because some drivers force VSync to on and we can't change it. + // In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/ + mVSyncWasEnabled = mWindow->isVSyncEnabled(); + #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) + mWindow->setVSyncEnabled(false); + #endif + setVisible(true); if (mFirstLoad) @@ -83,6 +92,12 @@ namespace MWGui void LoadingScreen::loadingOff() { + // Re-enable vsync now. + // In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/ + #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) + mWindow->setVSyncEnabled(mVSyncWasEnabled); + #endif + setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); @@ -212,7 +227,8 @@ namespace MWGui // caused a sync / flush and would be expensive). // We're doing this so we can do some actual loading while the GPU is busy with the render. // This means the render is lagging a frame behind, but this is hardly noticable. - mWindow->swapBuffers(false); // never Vsync, makes no sense here + mWindow->swapBuffers(); + mWindow->update(false); if (!hasCompositor) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index dde8ff63a..2d1d7431f 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -57,6 +57,8 @@ namespace MWGui Ogre::StringVector mResources; + bool mVSyncWasEnabled; + void changeWallpaper(); void draw(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 45da1bf17..48d7ec171 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -14,6 +14,7 @@ namespace MWGui mMessageBoxSpeed = 0.1; mInterMessageBoxe = NULL; mStaticMessageBox = NULL; + mLastButtonPressed = -1; } void MessageBoxManager::onFrame (float frameDuration) @@ -62,6 +63,7 @@ namespace MWGui } if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { + mLastButtonPressed = mInterMessageBoxe->readPressedButton(); delete mInterMessageBoxe; mInterMessageBoxe = NULL; MWBase::Environment::get().getInputManager()->changeInputMode( @@ -107,6 +109,7 @@ namespace MWGui } mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); + mLastButtonPressed = -1; return true; } @@ -154,11 +157,9 @@ namespace MWGui int MessageBoxManager::readPressedButton () { - if(mInterMessageBoxe != NULL) - { - return mInterMessageBoxe->readPressedButton(); - } - return -1; + int pressed = mLastButtonPressed; + mLastButtonPressed = -1; + return pressed; } @@ -421,9 +422,7 @@ namespace MWGui int InteractiveMessageBox::readPressedButton () { - int pressed = mButtonPressed; - mButtonPressed = -1; - return pressed; + return mButtonPressed; } } diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 4ef645f5e..63840cfe2 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -56,6 +56,7 @@ namespace MWGui MessageBox* mStaticMessageBox; std::vector mTimers; float mMessageBoxSpeed; + int mLastButtonPressed; }; class MessageBox : public OEngine::GUI::Layout diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 3dfa17bad..923b9d01d 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -363,8 +363,12 @@ namespace MWGui else if (_sender == mVSyncButton) { Settings::Manager::setBool("vsync", "Video", newState); + // Ogre::Window::setVSyncEnabled is bugged in 1.8 +#if OGRE_VERSION < (1 << 16 | 9 << 8 | 0) MWBase::Environment::get().getWindowManager()-> messageBox("VSync will be applied after a restart", std::vector()); +#endif + apply(); } else { diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 9812c0f8a..0c303485a 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -169,13 +172,34 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString( ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")"; - if (!(effect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType(); + if (displayType == ESM::MagicEffect::MDT_TimesInt) + { + std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", ""); + std::stringstream formatter; + formatter << std::fixed << std::setprecision(1) << " " << (effectIt->mMagnitude / 10.0f) << timesInt; + sourcesDescription += formatter.str(); + } + else if ( displayType != ESM::MagicEffect::MDT_None ) { - std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); - std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); - sourcesDescription += ": " + boost::lexical_cast(effectIt->mMagnitude); - sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? pts : pt); + + if ( displayType == ESM::MagicEffect::MDT_Percentage ) + sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); + else if ( displayType == ESM::MagicEffect::MDT_Feet ) + sourcesDescription += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", ""); + else if ( displayType == ESM::MagicEffect::MDT_Level ) + { + sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? + MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", "") : + MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", "") ); + } + else // ESM::MagicEffect::MDT_Points + { + sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? + MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : + MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); + } } } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index dea64ae8c..3fc3187e8 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include #include #include @@ -405,6 +408,10 @@ namespace MWGui std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string pct = MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); + std::string ft = MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", ""); + std::string lvl = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", ""); + std::string lvls = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", ""); std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); @@ -421,13 +428,32 @@ namespace MWGui spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); } - if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) - { - if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); - else - { - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; + if (mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) { + ESM::MagicEffect::MagnitudeDisplayType displayType = magicEffect->getMagnitudeDisplayType(); + if ( displayType == ESM::MagicEffect::MDT_TimesInt ) { + std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", ""); + std::stringstream formatter; + + formatter << std::fixed << std::setprecision(1) << " " << (mEffectParams.mMagnMin / 10.0f); + if (mEffectParams.mMagnMin != mEffectParams.mMagnMax) + formatter << to << (mEffectParams.mMagnMax / 10.0f); + formatter << timesInt; + + spellLine += formatter.str(); + } + else if ( displayType != ESM::MagicEffect::MDT_None ) { + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin); + if (mEffectParams.mMagnMin != mEffectParams.mMagnMax) + spellLine += to + boost::lexical_cast(mEffectParams.mMagnMax); + + if ( displayType == ESM::MagicEffect::MDT_Percentage ) + spellLine += pct; + else if ( displayType == ESM::MagicEffect::MDT_Feet ) + spellLine += " " + ft; + else if ( displayType == ESM::MagicEffect::MDT_Level ) + spellLine += " " + ((mEffectParams.mMagnMin == 1 && mEffectParams.mMagnMax == 1) ? lvl : lvls ); + else // ESM::MagicEffect::MDT_Points + spellLine += " " + ((mEffectParams.mMagnMin == 1 && mEffectParams.mMagnMax == 1) ? pt : pts ); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bf8b664da..4b4d2dfd1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -61,20 +61,23 @@ namespace MWGui const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding) - : mGuiManager(NULL) - , mConsoleOnlyScripts(consoleOnlyScripts) + : mConsoleOnlyScripts(consoleOnlyScripts) + , mGuiManager(NULL) , mRendering(ogre) , mHud(NULL) , mMap(NULL) , mMenu(NULL) - , mStatsWindow(NULL) , mToolTips(NULL) + , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) , mJournal(NULL) , mDialogueWindow(NULL) - , mBookWindow(NULL) + , mContainerWindow(NULL) + , mDragAndDrop(NULL) + , mInventoryWindow(NULL) , mScrollWindow(NULL) + , mBookWindow(NULL) , mCountDialog(NULL) , mTradeWindow(NULL) , mSpellBuyingWindow(NULL) @@ -83,27 +86,37 @@ namespace MWGui , mConfirmationDialog(NULL) , mAlchemyWindow(NULL) , mSpellWindow(NULL) + , mQuickKeysMenu(NULL) , mLoadingScreen(NULL) - , mCharGen(NULL) , mLevelupDialog(NULL) , mWaitDialog(NULL) , mSpellCreationDialog(NULL) , mEnchantingDialog(NULL) , mTrainingWindow(NULL) , mMerchantRepair(NULL) - , mRepair(NULL) , mSoulgemDialog(NULL) + , mRepair(NULL) , mCompanionWindow(NULL) + , mTranslationDataStorage (translationDataStorage) + , mSoftwareCursor(NULL) + , mCharGen(NULL) + , mInputBlocker(NULL) + , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) + , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) + , mHudEnabled(true) + , mCursorVisible(true) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() - , mPlayerMajorSkills() , mPlayerMinorSkills() + , mPlayerMajorSkills() , mPlayerSkillValues() , mPlayerHealth() , mPlayerMagicka() , mPlayerFatigue() , mGui(NULL) + , mGuiModes() + , mCursorManager(NULL) , mGarbageDialogs() , mShown(GW_ALL) , mForceHidden(GW_None) @@ -113,13 +126,7 @@ namespace MWGui , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) - , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) - , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) - , mHudEnabled(true) - , mTranslationDataStorage (translationDataStorage) - , mCursorManager(NULL) , mUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")) - , mCursorVisible(true) { // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 43f2bcc15..4746260ed 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -468,6 +468,41 @@ namespace MWInput bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { + // Cut, copy & paste + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (focus) + { + MyGUI::EditBox* edit = focus->castType(false); + if (edit && !edit->getEditReadOnly()) + { + if (arg.keysym.sym == SDLK_v && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) + { + char* text = SDL_GetClipboardText(); + + if (text) + { + edit->addText(MyGUI::UString(text)); + SDL_free(text); + } + } + if (arg.keysym.sym == SDLK_x && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) + { + std::string text = edit->getTextSelection(); + if (text.length()) + { + SDL_SetClipboardText(text.c_str()); + edit->deleteTextSelection(); + } + } + if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) + { + std::string text = edit->getTextSelection(); + if (text.length()) + SDL_SetClipboardText(text.c_str()); + } + } + } + mInputBinder->keyPressed (arg); if(arg.keysym.sym == SDLK_RETURN diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ca26e88ce..42851dea3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -31,18 +31,24 @@ namespace MWMechanics calculateDynamicStats (ptr); calculateCreatureStatModifiers (ptr); - // AI if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) { + // AI CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); creatureStats.getAiSequence().execute (ptr); + + // fatigue restoration + calculateRestoration(ptr, duration); } } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { if(!paused) + { updateDrowning(ptr, duration); + updateEquippedLight(ptr, duration); + } } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) @@ -93,39 +99,29 @@ namespace MWMechanics void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration) { CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + const MWWorld::Store& settings = MWBase::Environment::get().getWorld()->getStore().get(); + + int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); + + float capacity = MWWorld::Class::get(ptr).getCapacity(ptr); + float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr); + float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; if (duration == 3600) { - bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; + // the actor is sleeping, restore health and magicka - int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); + bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; DynamicStat health = stats.getHealth(); health.setCurrent (health.getCurrent() + 0.1 * endurance); stats.setHealth (health); - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - - float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat (); - float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat (); - float fEndFatigueMult = store.get().find("fEndFatigueMult")->getFloat (); - - float capacity = MWWorld::Class::get(ptr).getCapacity(ptr); - float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr); - float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity); - if (normalizedEncumbrance > 1) - normalizedEncumbrance = 1; - - float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); - x *= fEndFatigueMult * endurance; - - DynamicStat fatigue = stats.getFatigue(); - fatigue.setCurrent (fatigue.getCurrent() + 3600 * x); - stats.setFatigue (fatigue); - if (!stunted) { - float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat (); + float fRestMagicMult = settings.find("fRestMagicMult")->getFloat (); DynamicStat magicka = stats.getMagicka(); magicka.setCurrent (magicka.getCurrent() @@ -133,6 +129,19 @@ namespace MWMechanics stats.setMagicka (magicka); } } + + // restore fatigue + + float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat (); + float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat (); + float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat (); + + float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); + x *= fEndFatigueMult * endurance; + + DynamicStat fatigue = stats.getFatigue(); + fatigue.setCurrent (fatigue.getCurrent() + duration * x); + stats.setFatigue (fatigue); } void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr) @@ -196,6 +205,49 @@ namespace MWMechanics stats.setTimeToStartDrowning(20); } + void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) + { + //If holding a light... + MWWorld::InventoryStore &inventoryStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + MWWorld::ContainerStoreIterator heldIter = + inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + + if(heldIter.getType() == MWWorld::ContainerStore::Type_Light) + { + // Use time from the player's light + bool isPlayer = ptr.getRefData().getHandle()=="player"; + if(isPlayer) + { + float timeRemaining = heldIter->getClass().getRemainingUsageTime(*heldIter); + + // -1 is infinite light source. Other negative values are treated as 0. + if(timeRemaining != -1.0f) + { + timeRemaining -= duration; + + if(timeRemaining > 0.0f) + heldIter->getClass().setRemainingUsageTime(*heldIter, timeRemaining); + else + { + heldIter->getRefData().setCount(0); // remove it + return; + } + } + } + + // Both NPC and player lights extinguish in water. + if(MWBase::Environment::get().getWorld()->isSwimming(ptr)) + { + heldIter->getRefData().setCount(0); // remove it + + // ...But, only the player makes a sound. + if(isPlayer) + MWBase::Environment::get().getSoundManager()->playSound("torch out", + 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + } + } + } + Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) @@ -276,7 +328,8 @@ namespace MWMechanics } // If it's the player and God Mode is turned on, keep it alive - if(iter->first.getRefData().getHandle()=="player" && MWBase::Environment::get().getWorld()->getGodModeState()) + if(iter->first.getRefData().getHandle()=="player" && + MWBase::Environment::get().getWorld()->getGodModeState()) { MWMechanics::DynamicStat stat(stats.getHealth()); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 69878a000..a77e52ba3 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -44,6 +44,8 @@ namespace MWMechanics void updateDrowning (const MWWorld::Ptr& ptr, float duration); + void updateEquippedLight (const MWWorld::Ptr& ptr, float duration); + public: Actors(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ec2bb1b59..c4260d907 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -767,10 +767,25 @@ void CharacterController::update(float duration) } if(sneak || inwater || flying) + { vec.z = 0.0f; + mFallHeight = mPtr.getRefData().getPosition().pos[2]; + } if(!onground && !flying && !inwater) { + // The player is in the air (either getting up —ascending part of jump— or falling). + + if (world->isSlowFalling(mPtr)) + { + // SlowFalling spell effect is active, do not keep previous fall height + mFallHeight = mPtr.getRefData().getPosition().pos[2]; + } + else + { + mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]); + } + const MWWorld::Store &gmst = world->getStore().get(); forcestateupdate = (mJumpState != JumpState_Falling); @@ -794,6 +809,8 @@ void CharacterController::update(float duration) } else if(vec.z > 0.0f && mJumpState == JumpState_None) { + // The player has started a jump. + float z = cls.getJump(mPtr); if(vec.x == 0 && vec.y == 0) vec = Ogre::Vector3(0.0f, 0.0f, z); @@ -803,13 +820,49 @@ void CharacterController::update(float duration) vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; } - //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; + // advance acrobatics + cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); + + // decrease fatigue + const MWWorld::Store &gmst = world->getStore().get(); + const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); + const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); + const float normalizedEncumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr); + const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; + DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); + fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); + cls.getCreatureStats(mPtr).setFatigue(fatigue); } else if(mJumpState == JumpState_Falling) { + // The player is landing. + forcestateupdate = true; mJumpState = JumpState_Landing; vec.z = 0.0f; + + float healthLost = cls.getFallDamage(mPtr, mFallHeight - mPtr.getRefData().getPosition().pos[2]); + if (healthLost > 0.0f) + { + const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm(); + + // inflict fall damages + DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); + int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm); + health.setCurrent(health.getCurrent() - realHealthLost); + cls.getCreatureStats(mPtr).setHealth(health); + + // report acrobatics progression + cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); + + const float acrobaticsSkill = cls.getNpcStats(mPtr).getSkill(ESM::Skill::Acrobatics).getModified(); + if (healthLost > (acrobaticsSkill * fatigueTerm)) + { + //TODO: actor falls over + } + } + + mFallHeight = mPtr.getRefData().getPosition().pos[2]; } else { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c943b9597..8670b385e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/ptr.hpp" namespace MWWorld @@ -154,6 +156,9 @@ class CharacterController float mSecondsOfSwimming; float mSecondsOfRunning; + // used for acrobatics progress and fall damages + float mFallHeight; + std::string mAttackType; // slash, chop or thrust void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 36f53c0fe..9af3987a8 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -187,6 +187,12 @@ namespace MWRender rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); } + void Camera::setSneakOffset() + { + if(mAnimation) + mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -9.8f)); + } + float Camera::getYaw() { if(mVanity.enabled || mPreviewMode) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index dc552371e..baf2f3685 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -79,6 +79,12 @@ namespace MWRender void togglePreviewMode(bool enable); + /// \brief Lowers the camera for sneak. + /// As animation is tied to the camera, this needs + /// to be set each frame after the animation is + /// applied. + void setSneakOffset(); + bool isFirstPerson() const { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 13b5971e2..9ffe53eab 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -84,7 +84,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mWeapon(inv.end()), mShield(inv.end()), mViewMode(viewMode), - mShowWeapons(false) + mShowWeapons(false), + mFirstPersonOffset(0.f, 0.f, 0.f) { mNpc = mPtr.get()->mBase; @@ -392,6 +393,11 @@ void NpcAnimation::updateParts(bool forceupdate) } } +void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset) +{ + mFirstPersonOffset += offset; +} + class SetObjectGroup { int mGroup; @@ -448,7 +454,12 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) float pitch = mCamera->getPitch(); Ogre::Node *node = baseinst->getBone("Bip01 Neck"); node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD); + + // This has to be done before this function ends; + // updateSkeletonInstance, below, touches the hands. + node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); } + mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. for(size_t i = 0;i < ESM::PRT_Count;i++) { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 24205acaf..b1abf97af 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -64,6 +64,8 @@ private: int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[ESM::PRT_Count]; + Ogre::Vector3 mFirstPersonOffset; + void updateNpcBase(); NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename); @@ -89,6 +91,11 @@ public: void updateParts(bool forceupdate = false); + /// \brief Applies a translation to the arms and hands. + /// This may be called multiple times before the animation + /// is updated to add additional offsets. + void addFirstPersonOffset(const Ogre::Vector3 &offset); + /// Rebuilds the NPC, updating their root model, animation sources, and equipment. void rebuild(); }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e03b2ccfc..93425191d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -354,6 +354,15 @@ void RenderingManager::update (float duration, bool paused) mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); } + // Sink the camera while sneaking + bool isSneaking = MWWorld::Class::get(player).getStance(player, MWWorld::Class::Sneak); + bool isInAir = !world->isOnGround(player); + bool isSwimming = world->isSwimming(player); + + if(isSneaking && !(isSwimming || isInAir)) + mCamera->setSneakOffset(); + + mOcclusionQuery->update(duration); mVideoPlayer->update (); @@ -760,6 +769,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec || it->second == "resolution y" || it->second == "fullscreen")) changeRes = true; + else if (it->first == "Video" && it->second == "vsync") + { + // setVSyncEnabled is bugged in 1.8 +#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) + mRendering.getWindow()->setVSyncEnabled(Settings::Manager::getBool("vsync", "Video")); +#endif + } else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); else if ((it->second == "texture filtering" && it->first == "General") diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index ff3b60ca6..7bbb33699 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -352,5 +352,7 @@ op 0x200021c: SetWerewolfAcrobaticsExplicit op 0x200021d: ShowVars op 0x200021e: ShowVarsExplicit op 0x200021f: ToggleGodMode +op 0x2000220: DisableLevitation +op 0x2000221: EnableLevitation -opcodes 0x2000220-0x3ffffff unused +opcodes 0x2000222-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a8d8a5f2b..4ae1136e2 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -635,7 +635,18 @@ namespace MWScript world->enableTeleporting(Enable); } }; - + + template + class OpEnableLevitation : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->enableLevitation(Enable); + } + }; template class OpShowVars : public Interpreter::Opcode0 @@ -789,6 +800,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeShowVarsExplicit, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); + interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation); + interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation); } } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c739ea831..d3d1aff49 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -132,6 +132,16 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } + void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const + { + throw std::runtime_error ("class does not support time-based uses"); + } + + float Class::getRemainingUsageTime (const Ptr& ptr) const + { + throw std::runtime_error ("class does not support time-based uses"); + } + std::string Class::getScript (const Ptr& ptr) const { return ""; @@ -167,6 +177,11 @@ namespace MWWorld throw std::runtime_error ("class does not support enchanting"); } + float Class::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const + { + return 0; + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 28e37cbf3..2db293e68 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -156,6 +156,14 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) + virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; + ///< Sets the remaining duration of the object, such as an equippable light + /// source. (default implementation: throw an exception) + + virtual float getRemainingUsageTime (const Ptr& ptr) const; + ///< Returns the remaining duration of the object, such as an equippable light + /// source. (default implementation: throw an exception) + virtual std::string getScript (const Ptr& ptr) const; ///< Return name of the script attached to ptr (default implementation: return an empty /// string). @@ -175,6 +183,9 @@ namespace MWWorld virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) + virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const; + ///< Return amount of health points lost when falling + virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2ee23dbd6..90452f661 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -656,26 +656,38 @@ namespace MWWorld return iterator(mSharedExt.end()); } - /// \todo implement appropriate index + // Return the northernmost cell in the easternmost column. const ESM::Cell *searchExtByName(const std::string &id) const { + ESM::Cell *cell = 0; std::vector::const_iterator it = mSharedExt.begin(); for (; it != mSharedExt.end(); ++it) { if (Misc::StringUtils::ciEqual((*it)->mName, id)) { - return *it; + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } } } - return 0; + return cell; } - /// \todo implement appropriate index + // Return the northernmost cell in the easternmost column. const ESM::Cell *searchExtByRegion(const std::string &id) const { + ESM::Cell *cell = 0; std::vector::const_iterator it = mSharedExt.begin(); for (; it != mSharedExt.end(); ++it) { if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { - return *it; + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } } } - return 0; + return cell; } size_t getSize() const { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f3d4c81b7..9635feaf3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -225,8 +225,8 @@ namespace MWWorld if (mEsm[0].getFormat() == 0) ensureNeededRecords(); - mStore.movePlayerRecord(); mStore.setUp(); + mStore.movePlayerRecord(); mGlobalVariables = new Globals (mStore); @@ -1582,6 +1582,19 @@ namespace MWWorld return false; } + bool + World::isSlowFalling(const MWWorld::Ptr &ptr) const + { + if(!ptr.getClass().isActor()) + return false; + + const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); + if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::SlowFall)).mMagnitude > 0) + return true; + + return false; + } + bool World::isSubmerged(const MWWorld::Ptr &object) const { float *fpos = object.getRefData().getPosition().pos; @@ -1877,6 +1890,16 @@ namespace MWWorld return mTeleportEnabled; } + void World::enableLevitation(bool enable) + { + mLevitationEnabled = enable; + } + + bool World::isLevitationEnabled() const + { + return mLevitationEnabled; + } + void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) { MWMechanics::NpcStats& npcStats = Class::get(actor).getNpcStats(actor); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 53b01f1ab..e275756e8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -116,6 +116,7 @@ namespace MWWorld int mPlayIntro; bool mTeleportEnabled; + bool mLevitationEnabled; public: @@ -355,6 +356,7 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); virtual bool isFlying(const MWWorld::Ptr &ptr) const; + virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; @@ -438,6 +440,12 @@ namespace MWWorld /// Returns true if teleport spell effects are allowed. virtual bool isTeleportingEnabled() const; + /// Enables or disables use of levitation spell effect. + virtual void enableLevitation(bool enable); + + /// Returns true if levitation spell effect is allowed. + virtual bool isLevitationEnabled() const; + virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 415f8d168..65f6e112a 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -260,6 +260,8 @@ namespace Compiler extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit); extensions.registerInstruction("tgm", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); + extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); + extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 5eb54208a..aca24e0d3 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -222,6 +222,8 @@ namespace Compiler const int opcodeShowVars = 0x200021d; const int opcodeShowVarsExplicit = 0x200021e; const int opcodeToggleGodMode = 0x200021f; + const int opcodeDisableLevitation = 0x2000220; + const int opcodeEnableLevitation = 0x2000221; } namespace Sky diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 060645b5f..19d535600 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -274,5 +274,23 @@ short MagicEffect::effectStringToId(const std::string &effect) return name->first; } +MagicEffect::MagnitudeDisplayType MagicEffect::getMagnitudeDisplayType() const { + if ( mData.mFlags & NoMagnitude ) + return MDT_None; + if ( mIndex == 84 ) + return MDT_TimesInt; + if ( mIndex == 59 || + ( mIndex >= 64 && mIndex <= 66) ) + return MDT_Feet; + if ( mIndex == 118 || mIndex == 119 ) + return MDT_Level; + if ( ( mIndex >= 28 && mIndex <= 36 ) + || ( mIndex >= 90 && mIndex <= 99 ) + || mIndex == 40 || mIndex == 47 + || mIndex == 57 || mIndex == 68 ) + return MDT_Percentage; + + return MDT_Points; +} } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index b74efb466..f139fa32c 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -32,6 +32,15 @@ struct MagicEffect Negative = 0x0800 // A harmful effect. Will determine whether // eg. NPCs regard this spell as an attack. (same as 0x10?) }; + enum MagnitudeDisplayType + { + MDT_None, + MDT_Feet, + MDT_Level, + MDT_Percentage, + MDT_Points, + MDT_TimesInt + }; struct MEDTstruct { @@ -47,6 +56,7 @@ struct MagicEffect static const std::string &effectIdToString(short effectID); static short effectStringToId(const std::string &effect); + MagnitudeDisplayType getMagnitudeDisplayType() const; MEDTstruct mData; diff --git a/credits.txt b/credits.txt index 6e8e36612..bd0c6ca74 100644 --- a/credits.txt +++ b/credits.txt @@ -12,6 +12,7 @@ Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) Aleksandar Jovanov +Alex Haddad (rainChu) Alex McKibben (WeirdSexy) Alexander Nadeau (wareya) Alexander Olofsson (Ace) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 931d6aca3..df74bba3b 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -30,9 +30,6 @@ namespace SFO InputWrapper::~InputWrapper() { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; } void InputWrapper::capture(bool windowEventsOnly) diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index bfda40c68..7d24a283e 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -9,6 +9,7 @@ + diff --git a/issue912 b/issue912 deleted file mode 100644 index 604cc392c..000000000 --- a/issue912 +++ /dev/null @@ -1 +0,0 @@ -branch for issue912