mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 12:39:55 +00:00
commit
1b56074b53
@ -134,6 +134,9 @@ if(USE_SYSTEM_TINYXML)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TES4
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
# Platform specific
|
||||
if (WIN32)
|
||||
if(NOT MINGW)
|
||||
@ -257,9 +260,10 @@ include_directories("." ${LIBS_DIR}
|
||||
${MYGUI_PLATFORM_INCLUDE_DIRS}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${BULLET_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
|
||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR} ${ZLIB_LIB_DIR})
|
||||
|
||||
if(MYGUI_STATIC)
|
||||
add_definitions(-DMYGUI_STATIC)
|
||||
@ -577,6 +581,7 @@ add_subdirectory (extern/ogre-ffmpeg-videoplayer)
|
||||
add_subdirectory (extern/oics)
|
||||
add_subdirectory (extern/sdl4ogre)
|
||||
add_subdirectory (extern/murmurhash)
|
||||
add_subdirectory (extern/BSAOpt)
|
||||
|
||||
# Components
|
||||
add_subdirectory (components)
|
||||
|
24
README.md
24
README.md
@ -17,7 +17,7 @@ Font Licenses:
|
||||
Wrong Way, Go Back
|
||||
------------------
|
||||
|
||||
This is a fork of an old version of OpenMW. This version is probably not what you are looking for. It is still stuck on Ogre 1.9 and hence does not have any of the recent graphics enhancements. I suggest you use the [official release](https://github.com/OpenMW/openmw) instead.
|
||||
This is a fork of an old version of OpenMW. This version is probably not what you are looking for. It is still stuck on Ogre 1.10 and hence does not have any of the recent graphics enhancements. I suggest you use the [official release](https://github.com/OpenMW/openmw) instead.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
@ -106,11 +106,9 @@ Command line options
|
||||
Changes
|
||||
-------
|
||||
|
||||
Some of the differences with the official release are listed below. They are almost all to do with OpenCS.
|
||||
Some of the differences with the official release are listed below. Initial changes are mostly to do with OpenCS:
|
||||
|
||||
* Various minor bug fixes.
|
||||
* Experimental support of loading TES4/TES5 records (coming soon).
|
||||
* Experimental support of navMesh (coming soon).
|
||||
* C++11 features are used (or at least those available on MSVC 2013 onwards).
|
||||
* Loading time improvements.
|
||||
* Loading progress bar changes.
|
||||
@ -125,3 +123,21 @@ Some of the differences with the official release are listed below. They are al
|
||||
* User preferences setting to workaround some X window managers not keeping pre-maximised state.
|
||||
* Use opencs.ini to store window states between sessions.
|
||||
|
||||
Enhancements for both OpenMW and OpenCS:
|
||||
|
||||
* Hash based lookup for TES3 BSA files.
|
||||
* TES4/TES5 BSA support.
|
||||
* Experimental support of loading TES4/TES5 records (coming soon).
|
||||
* Experimental support of NavMesh (eventually).
|
||||
|
||||
Build Dependencies
|
||||
------------------
|
||||
|
||||
The development was done using MSVC 2013 then MS Visual Studio Community 2015, Version 14.0.25431.01 Update 3. The code may or may not compile under linux/gcc (probably not).
|
||||
|
||||
* bost-1_63
|
||||
* Ogre 1.10.0
|
||||
* ffmpeg-20140823-git-7444cf9-win64-dev
|
||||
* zlib 1.2.8
|
||||
* Qt5
|
||||
|
||||
|
@ -378,7 +378,7 @@ public:
|
||||
bool isDeleted = false;
|
||||
|
||||
faction.load(esm, isDeleted);
|
||||
std::string id = Misc::StringUtils::toLower(faction.mId);
|
||||
std::string id = Misc::StringUtils::lowerCase(faction.mId);
|
||||
|
||||
for (std::map<std::string, int>::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it)
|
||||
{
|
||||
@ -395,7 +395,7 @@ public:
|
||||
virtual void read(ESM::ESMReader &esm)
|
||||
{
|
||||
std::string itemid = esm.getHNString("NAME");
|
||||
Misc::StringUtils::toLower(itemid);
|
||||
Misc::StringUtils::lowerCaseInPlace(itemid);
|
||||
|
||||
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
|
||||
{
|
||||
|
@ -847,7 +847,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
|
||||
|
||||
for(std::vector<std::string>::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
|
||||
std::string filetype(entry->substr(entry->length()-3));
|
||||
Misc::StringUtils::toLower(filetype);
|
||||
Misc::StringUtils::lowerCaseInPlace(filetype);
|
||||
|
||||
if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) {
|
||||
boost::filesystem::path filepath(gameFilesDir);
|
||||
|
@ -211,7 +211,9 @@ target_link_libraries(openmw-cs
|
||||
${OGRE_Overlay_LIBRARIES}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${SHINY_LIBRARIES}
|
||||
${ZLIB_LIBRARY}
|
||||
${MURMURHASH_LIBRARIES}
|
||||
${BSAOPTHASH_LIBRARIES}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
|
@ -30,6 +30,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
||||
{
|
||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||
std::vector<std::string> tes4config = readTES4Config();
|
||||
|
||||
setupDataFiles (config.first);
|
||||
|
||||
@ -44,6 +45,9 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||
|
||||
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
|
||||
mFsStrict);
|
||||
// useLooseFiles is set false, since it is already done above
|
||||
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), tes4config, /*useLooseFiles*/false,
|
||||
mFsStrict, /*isTes4*/true);
|
||||
|
||||
mDocumentManager.listResources();
|
||||
|
||||
@ -182,6 +186,19 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||
return std::make_pair (canonicalPaths, variables["fallback-archive"].as<std::vector<std::string> >());
|
||||
}
|
||||
|
||||
std::vector<std::string> CS::Editor::readTES4Config()
|
||||
{
|
||||
boost::program_options::variables_map variables;
|
||||
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
|
||||
|
||||
desc.add_options()
|
||||
("fallback-tes4archive", boost::program_options::value<std::vector<std::string> >()->
|
||||
default_value(std::vector<std::string>(), "fallback-tes4archive")->multitoken());
|
||||
|
||||
mCfgMgr.readConfiguration(variables, desc, /*quiet*/true);
|
||||
return variables["fallback-tes4archive"].as<std::vector<std::string> >();
|
||||
}
|
||||
|
||||
void CS::Editor::createGame()
|
||||
{
|
||||
mStartup.hide();
|
||||
|
@ -73,6 +73,7 @@ namespace CS
|
||||
void setupDataFiles (const Files::PathContainer& dataDirs);
|
||||
|
||||
std::pair<Files::PathContainer, std::vector<std::string> > readConfig(bool quiet=false);
|
||||
std::vector<std::string> readTES4Config();
|
||||
///< \return data paths
|
||||
|
||||
// not implemented
|
||||
|
@ -93,7 +93,7 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked)
|
||||
void CSMWorld::CommandDispatcher::setSelection (const std::vector<std::string>& selection)
|
||||
{
|
||||
mSelection = selection;
|
||||
std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLower);
|
||||
std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::lowerCaseInPlace);
|
||||
std::sort (mSelection.begin(), mSelection.end());
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ void CSMWorld::RegionMap::updateRegions (const std::vector<std::string>& regions
|
||||
{
|
||||
std::vector<std::string> regions2 (regions);
|
||||
|
||||
std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase);
|
||||
std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::lowerCaseInPlace);
|
||||
std::sort (regions2.begin(), regions2.end());
|
||||
|
||||
for (std::map<CellCoordinates, CellDescription>::const_iterator iter (mMap.begin());
|
||||
|
@ -93,7 +93,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
||||
{
|
||||
mIds = mData.getIds();
|
||||
|
||||
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::toLower);
|
||||
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCaseInPlace);
|
||||
std::sort (mIds.begin(), mIds.end());
|
||||
|
||||
mIdsUpdated = true;
|
||||
|
@ -117,6 +117,8 @@ target_link_libraries(openmw
|
||||
${OGRE_LIBRARIES}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${SHINY_LIBRARIES}
|
||||
${BSAOPTHASH_LIBRARIES}
|
||||
${ZLIB_LIBRARY}
|
||||
${OPENAL_LIBRARY}
|
||||
${SOUND_INPUT_LIBRARY}
|
||||
${BULLET_LIBRARIES}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
@ -194,7 +194,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||
, mNewGame (false)
|
||||
, mCfgMgr(configurationManager)
|
||||
{
|
||||
OEngine::Misc::Rng::init();
|
||||
Misc::Rng::init();
|
||||
std::srand ( static_cast<unsigned int>(std::time(NULL)) );
|
||||
MWClass::registerClasses();
|
||||
|
||||
@ -252,6 +252,10 @@ void OMW::Engine::addArchive (const std::string& archive) {
|
||||
mArchives.push_back(archive);
|
||||
}
|
||||
|
||||
void OMW::Engine::addTES4Archive (const std::string& archive) {
|
||||
mTES4Archives.push_back(archive);
|
||||
}
|
||||
|
||||
// Set resource dir
|
||||
void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir)
|
||||
{
|
||||
@ -365,6 +369,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
mOgre->createWindow("OpenMW", windowSettings);
|
||||
|
||||
Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict);
|
||||
// useLooseFiles is set false, since it is already done above
|
||||
Bsa::registerResources (mFileCollections, mTES4Archives, /*useLooseFiles*/false, mFSStrict, /*isTes4*/true);
|
||||
|
||||
// Create input and UI first to set up a bootstrapping environment for
|
||||
// showing a loading screen and keeping the window responsive while doing so
|
||||
|
@ -67,6 +67,7 @@ namespace OMW
|
||||
ToUTF8::Utf8Encoder* mEncoder;
|
||||
Files::PathContainer mDataDirs;
|
||||
std::vector<std::string> mArchives;
|
||||
std::vector<std::string> mTES4Archives;
|
||||
boost::filesystem::path mResDir;
|
||||
OEngine::Render::OgreRenderer *mOgre;
|
||||
std::string mCellName;
|
||||
@ -137,6 +138,7 @@ namespace OMW
|
||||
|
||||
/// Add BSA archive
|
||||
void addArchive(const std::string& archive);
|
||||
void addTES4Archive(const std::string& archive);
|
||||
|
||||
/// Set resource dir
|
||||
void setResourceDir(const boost::filesystem::path& parResDir);
|
||||
|
@ -112,6 +112,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||
("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
|
||||
->multitoken(), "set fallback BSA archives (later archives have higher priority)")
|
||||
|
||||
("fallback-tes4archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-tes4archive")
|
||||
->multitoken(), "set fallback TES4 BSA archives (later archives have higher priority)")
|
||||
|
||||
("resources", bpo::value<std::string>()->default_value("resources"),
|
||||
"set resources directory")
|
||||
|
||||
@ -240,6 +243,12 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||
engine.addArchive(*it);
|
||||
}
|
||||
|
||||
StringsVector tes4archives = variables["fallback-tes4archive"].as<StringsVector>();
|
||||
for (StringsVector::const_iterator it = tes4archives.begin(); it != tes4archives.end(); ++it)
|
||||
{
|
||||
engine.addTES4Archive(*it);
|
||||
}
|
||||
|
||||
engine.setResourceDir(variables["resources"].as<std::string>());
|
||||
|
||||
StringsVector content = variables["content"].as<StringsVector>();
|
||||
|
@ -146,11 +146,11 @@ namespace MWClass
|
||||
|
||||
// make key id lowercase
|
||||
std::string keyId = ptr.getCellRef().getKey();
|
||||
Misc::StringUtils::toLower(keyId);
|
||||
Misc::StringUtils::lowerCaseInPlace(keyId);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
std::string refId = it->getCellRef().getRefId();
|
||||
Misc::StringUtils::toLower(refId);
|
||||
Misc::StringUtils::lowerCaseInPlace(refId);
|
||||
if (refId == keyId)
|
||||
{
|
||||
hasKey = true;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "creature.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
@ -250,7 +250,7 @@ namespace MWClass
|
||||
|
||||
float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat);
|
||||
|
||||
if(OEngine::Misc::Rng::roll0to99() >= hitchance)
|
||||
if(Misc::Rng::rollProbability() >= hitchance/100.0f)
|
||||
{
|
||||
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
|
||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
|
||||
@ -376,7 +376,7 @@ namespace MWClass
|
||||
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat();
|
||||
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
|
||||
* getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt();
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99())
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
|
||||
{
|
||||
getCreatureStats(ptr).setKnockedDown(true);
|
||||
|
||||
@ -680,7 +680,7 @@ namespace MWClass
|
||||
++sound;
|
||||
}
|
||||
if(!sounds.empty())
|
||||
return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound;
|
||||
return sounds[Misc::Rng::rollDice(sounds.size())]->mSound;
|
||||
}
|
||||
|
||||
if (type == ESM::SoundGenerator::Land)
|
||||
|
@ -113,11 +113,11 @@ namespace MWClass
|
||||
|
||||
// make key id lowercase
|
||||
std::string keyId = ptr.getCellRef().getKey();
|
||||
Misc::StringUtils::toLower(keyId);
|
||||
Misc::StringUtils::lowerCaseInPlace(keyId);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
std::string refId = it->getCellRef().getRefId();
|
||||
Misc::StringUtils::toLower(refId);
|
||||
Misc::StringUtils::lowerCaseInPlace(refId);
|
||||
if (refId == keyId)
|
||||
{
|
||||
hasKey = true;
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
@ -382,7 +380,7 @@ namespace MWClass
|
||||
|
||||
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
|
||||
|
||||
if (OEngine::Misc::Rng::roll0to99() >= hitchance)
|
||||
if (Misc::Rng::rollProbability() >= hitchance / 100.0f)
|
||||
{
|
||||
othercls.onHit(victim, 0.0f, false, weapon, ptr, false);
|
||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
|
||||
@ -512,7 +510,7 @@ namespace MWClass
|
||||
const GMST& gmst = getGmst();
|
||||
|
||||
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
|
||||
if (OEngine::Misc::Rng::roll0to99() < chance)
|
||||
if (Misc::Rng::roll0to99() < chance)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
||||
}
|
||||
@ -521,7 +519,7 @@ namespace MWClass
|
||||
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat();
|
||||
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
|
||||
* gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt();
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99())
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
|
||||
{
|
||||
getCreatureStats(ptr).setKnockedDown(true);
|
||||
|
||||
@ -547,7 +545,7 @@ namespace MWClass
|
||||
MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron,
|
||||
MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet
|
||||
};
|
||||
int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)];
|
||||
int hitslot = hitslots[Misc::Rng::rollDice(20)];
|
||||
|
||||
float unmitigatedDamage = damage;
|
||||
float x = damage / (damage + getArmorRating(ptr));
|
||||
|
@ -18,11 +18,8 @@ namespace MWClass
|
||||
|
||||
void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Static> *ref =
|
||||
ptr.get<ESM::Static>();
|
||||
|
||||
if (!model.empty()) {
|
||||
renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ namespace MWGui
|
||||
size_t tagNameEndPos = tag.find(' ');
|
||||
mAttributes.clear();
|
||||
mTag = tag.substr(0, tagNameEndPos);
|
||||
Misc::StringUtils::toLower(mTag);
|
||||
Misc::StringUtils::lowerCaseInPlace(mTag);
|
||||
if (mTag.empty())
|
||||
return;
|
||||
|
||||
@ -151,7 +151,7 @@ namespace MWGui
|
||||
return;
|
||||
|
||||
std::string key = tag.substr(0, sepPos);
|
||||
Misc::StringUtils::toLower(key);
|
||||
Misc::StringUtils::lowerCaseInPlace(key);
|
||||
tag.erase(0, sepPos+1);
|
||||
|
||||
std::string value;
|
||||
|
@ -35,7 +35,7 @@ namespace MWGui
|
||||
{
|
||||
const ESM::GameSetting ¤tSetting = *currentIteration;
|
||||
std::string currentGMSTID = currentSetting.mId;
|
||||
Misc::StringUtils::toLower(currentGMSTID);
|
||||
Misc::StringUtils::lowerCaseInPlace(currentGMSTID);
|
||||
|
||||
// Don't bother checking this GMST if it's not a sMagicBound* one.
|
||||
const std::string& toFind = "smagicbound";
|
||||
@ -44,7 +44,7 @@ namespace MWGui
|
||||
|
||||
// All sMagicBound* GMST's should be of type string
|
||||
std::string currentGMSTValue = currentSetting.getString();
|
||||
Misc::StringUtils::toLower(currentGMSTValue);
|
||||
Misc::StringUtils::lowerCaseInPlace(currentGMSTValue);
|
||||
|
||||
boundItemIDCache.insert(currentGMSTValue);
|
||||
}
|
||||
@ -52,7 +52,7 @@ namespace MWGui
|
||||
|
||||
// Perform bound item check and assign the Flag_Bound bit if it passes
|
||||
std::string tempItemID = base.getCellRef().getRefId();
|
||||
Misc::StringUtils::toLower(tempItemID);
|
||||
Misc::StringUtils::lowerCaseInPlace(tempItemID);
|
||||
|
||||
if (boundItemIDCache.count(tempItemID) != 0)
|
||||
mFlags |= Flag_Bound;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <MyGUI_ScrollBar.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
@ -85,7 +85,7 @@ namespace MWGui
|
||||
std::set<int> skills;
|
||||
for (int day=0; day<mDays; ++day)
|
||||
{
|
||||
int skill = OEngine::Misc::Rng::rollDice(ESM::Skill::Length);
|
||||
int skill = Misc::Rng::rollDice(ESM::Skill::Length);
|
||||
skills.insert(skill);
|
||||
|
||||
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill);
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <MyGUI_Gui.h>
|
||||
#include <MyGUI_TextBox.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
@ -148,7 +148,7 @@ namespace MWGui
|
||||
|
||||
if (!mResources.empty())
|
||||
{
|
||||
std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size()));
|
||||
std::string const & randomSplash = mResources.at(Misc::Rng::rollDice(mResources.size()));
|
||||
|
||||
Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "pickpocketitemmodel.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
@ -20,7 +20,7 @@ namespace MWGui
|
||||
{
|
||||
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
||||
{
|
||||
if (OEngine::Misc::Rng::roll0to99() > chance)
|
||||
if (chance <= Misc::Rng::roll0to99())
|
||||
mHiddenItems.push_back(mSourceModel->getItem(i));
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <MyGUI_ScrollView.h>
|
||||
#include <MyGUI_Gui.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
@ -165,7 +165,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
|
||||
intelligenceTerm = 1;
|
||||
|
||||
float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm();
|
||||
int roll = OEngine::Misc::Rng::roll0to99();
|
||||
int roll = Misc::Rng::roll0to99();
|
||||
if (roll < x)
|
||||
{
|
||||
std::string soul = gem.getCellRef().getSoul();
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <MyGUI_InputManager.h>
|
||||
#include <MyGUI_ControllerManager.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/widgets/numericeditbox.hpp>
|
||||
|
||||
@ -368,7 +368,7 @@ namespace MWGui
|
||||
else
|
||||
x += abs(int(npcTerm - pcTerm));
|
||||
|
||||
int roll = OEngine::Misc::Rng::rollDice(100) + 1;
|
||||
int roll = Misc::Rng::rollDice(100) + 1;
|
||||
if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <MyGUI_ProgressBar.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/widgets/box.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
@ -155,9 +155,8 @@ namespace MWGui
|
||||
if (!region->mSleepList.empty())
|
||||
{
|
||||
// figure out if player will be woken while sleeping
|
||||
int x = OEngine::Misc::Rng::rollDice(hoursToWait);
|
||||
float fSleepRandMod = world->getStore().get<ESM::GameSetting>().find("fSleepRandMod")->getFloat();
|
||||
if (x < fSleepRandMod * hoursToWait)
|
||||
if (Misc::Rng::rollProbability() > fSleepRandMod)
|
||||
{
|
||||
float fSleepRestMod = world->getStore().get<ESM::GameSetting>().find("fSleepRestMod")->getFloat();
|
||||
mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "activespells.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
@ -132,15 +132,11 @@ namespace MWMechanics
|
||||
return scaledDuration-usedUp;
|
||||
}
|
||||
|
||||
bool ActiveSpells::isSpellActive(std::string id) const
|
||||
bool ActiveSpells::isSpellActive(const std::string& id) const
|
||||
{
|
||||
Misc::StringUtils::toLower(id);
|
||||
for (TContainer::iterator iter = mSpells.begin(); iter != mSpells.end(); ++iter)
|
||||
{
|
||||
std::string left = iter->first;
|
||||
Misc::StringUtils::toLower(left);
|
||||
|
||||
if (iter->first == id)
|
||||
if (Misc::StringUtils::ciEqual(iter->first, id))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -231,7 +227,7 @@ namespace MWMechanics
|
||||
{
|
||||
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); )
|
||||
{
|
||||
if (OEngine::Misc::Rng::roll0to99() < chance)
|
||||
if (Misc::Rng::roll0to99() < chance)
|
||||
mSpells.erase(it++);
|
||||
else
|
||||
++it;
|
||||
|
@ -97,7 +97,7 @@ namespace MWMechanics
|
||||
/// Remove all spells
|
||||
void clear();
|
||||
|
||||
bool isSpellActive (std::string id) const;
|
||||
bool isSpellActive (const std::string& id) const;
|
||||
///< case insensitive
|
||||
|
||||
const MagicEffects& getMagicEffects() const;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <OgreMath.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/aisequence.hpp>
|
||||
|
||||
@ -395,7 +395,7 @@ namespace MWMechanics
|
||||
if (!distantCombat) attackType = chooseBestAttack(weapon, movement);
|
||||
else attackType = ESM::Weapon::AT_Chop; // cause it's =0
|
||||
|
||||
strength = OEngine::Misc::Rng::rollClosedProbability();
|
||||
strength = Misc::Rng::rollClosedProbability();
|
||||
|
||||
// Note: may be 0 for some animations
|
||||
timerAttack = minMaxAttackDuration[attackType][0] +
|
||||
@ -406,7 +406,7 @@ namespace MWMechanics
|
||||
{
|
||||
const MWWorld::ESMStore &store = world->getStore();
|
||||
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->getInt();
|
||||
if (OEngine::Misc::Rng::roll0to99() < chance)
|
||||
if (Misc::Rng::roll0to99() < chance)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
|
||||
}
|
||||
@ -513,17 +513,17 @@ namespace MWMechanics
|
||||
{
|
||||
if(movement.mPosition[0] || movement.mPosition[1])
|
||||
{
|
||||
timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability();
|
||||
timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability();
|
||||
combatMove = true;
|
||||
}
|
||||
// only NPCs are smart enough to use dodge movements
|
||||
else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2)))
|
||||
{
|
||||
//apply sideway movement (kind of dodging) with some probability
|
||||
if (OEngine::Misc::Rng::rollClosedProbability() < 0.25)
|
||||
if (Misc::Rng::rollClosedProbability() < 0.25)
|
||||
{
|
||||
movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f;
|
||||
timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability();
|
||||
movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f;
|
||||
timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability();
|
||||
combatMove = true;
|
||||
}
|
||||
}
|
||||
@ -638,7 +638,7 @@ namespace MWMechanics
|
||||
float s2 = speed2 * t;
|
||||
float t_swing =
|
||||
minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] +
|
||||
(minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability();
|
||||
(minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * Misc::Rng::rollClosedProbability();
|
||||
|
||||
if (t + s2/speed1 <= t_swing)
|
||||
{
|
||||
@ -750,10 +750,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics:
|
||||
if (weapon == NULL)
|
||||
{
|
||||
//hand-to-hand deal equal damage for each type
|
||||
float roll = OEngine::Misc::Rng::rollClosedProbability();
|
||||
float roll = Misc::Rng::rollClosedProbability();
|
||||
if(roll <= 0.333f) //side punch
|
||||
{
|
||||
movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f;
|
||||
movement.mPosition[0] = Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f;
|
||||
movement.mPosition[1] = 0;
|
||||
attackType = ESM::Weapon::AT_Slash;
|
||||
}
|
||||
@ -777,10 +777,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics:
|
||||
|
||||
float total = static_cast<float>(slash + chop + thrust);
|
||||
|
||||
float roll = OEngine::Misc::Rng::rollClosedProbability();
|
||||
float roll = Misc::Rng::rollClosedProbability();
|
||||
if(roll <= (slash/total))
|
||||
{
|
||||
movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f;
|
||||
movement.mPosition[0] = (Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f;
|
||||
movement.mPosition[1] = 0;
|
||||
attackType = ESM::Weapon::AT_Slash;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <OgreVector3.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/aisequence.hpp>
|
||||
|
||||
@ -329,7 +329,7 @@ namespace MWMechanics
|
||||
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
|
||||
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
||||
|
||||
float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f;
|
||||
float roll = Misc::Rng::rollProbability() * 10000.0f;
|
||||
|
||||
// In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds
|
||||
// due to the roll being an integer.
|
||||
@ -504,7 +504,7 @@ namespace MWMechanics
|
||||
if(!storage.mPathFinder.isPathConstructed())
|
||||
{
|
||||
assert(mAllowedNodes.size());
|
||||
unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size());
|
||||
unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size());
|
||||
// NOTE: initially constructed with local (i.e. cell) co-ordinates
|
||||
Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode]));
|
||||
|
||||
@ -631,7 +631,7 @@ namespace MWMechanics
|
||||
.get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||
|
||||
unsigned short idleChance = static_cast<unsigned short>(fIdleChanceMultiplier * mIdle[counter]);
|
||||
unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier));
|
||||
unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier));
|
||||
if(randSelect < idleChance && randSelect > idleRoll)
|
||||
{
|
||||
playedIdle = counter+2;
|
||||
@ -653,7 +653,7 @@ namespace MWMechanics
|
||||
|
||||
state.moveIn(new AiWanderStorage());
|
||||
|
||||
int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size());
|
||||
int index = Misc::Rng::rollDice(mAllowedNodes.size());
|
||||
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
||||
|
||||
// apply a slight offset to prevent overcrowding
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/loadappa.hpp>
|
||||
@ -298,7 +298,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name)
|
||||
|
||||
newRecord.mName = name;
|
||||
|
||||
int index = OEngine::Misc::Rng::rollDice(6);
|
||||
int index = Misc::Rng::rollDice(6);
|
||||
assert (index>=0 && index<6);
|
||||
|
||||
static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" };
|
||||
@ -474,7 +474,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
|
||||
return Result_RandomFailure;
|
||||
}
|
||||
|
||||
if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99())
|
||||
if (getAlchemyFactor() < Misc::Rng::roll0to99())
|
||||
{
|
||||
removeIngredients();
|
||||
return Result_RandomFailure;
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "creaturestats.hpp"
|
||||
#include "security.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
@ -222,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i
|
||||
while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1)))
|
||||
++numAnims;
|
||||
|
||||
int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims]
|
||||
int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims]
|
||||
if (num)
|
||||
*num = roll;
|
||||
return prefix + Ogre::StringConverter::toString(roll);
|
||||
@ -831,7 +831,7 @@ bool CharacterController::updateCreatureState()
|
||||
}
|
||||
if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
|
||||
{
|
||||
int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2]
|
||||
int roll = Misc::Rng::rollDice(3); // [0, 2]
|
||||
if (roll == 0)
|
||||
mCurrentWeapon = "attack1";
|
||||
else if (roll == 1)
|
||||
@ -1127,7 +1127,7 @@ bool CharacterController::updateWeaponState()
|
||||
// most creatures don't actually have an attack wind-up animation, so use a uniform random value
|
||||
// (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings)
|
||||
// Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far.
|
||||
attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability());
|
||||
attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
||||
}
|
||||
|
||||
if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
@ -109,7 +109,7 @@ namespace MWMechanics
|
||||
int iBlockMinChance = gmst.find("iBlockMinChance")->getInt();
|
||||
x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x));
|
||||
|
||||
if (OEngine::Misc::Rng::roll0to99() < x)
|
||||
if (Misc::Rng::roll0to99() < x)
|
||||
{
|
||||
// Reduce shield durability by incoming damage
|
||||
int shieldhealth = shield->getClass().getItemHealth(*shield);
|
||||
@ -187,7 +187,7 @@ namespace MWMechanics
|
||||
int skillValue = attacker.getClass().getSkill(attacker,
|
||||
weapon.getClass().getEquipmentSkill(weapon));
|
||||
|
||||
if (OEngine::Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
|
||||
if (Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f)
|
||||
{
|
||||
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false);
|
||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker);
|
||||
@ -225,7 +225,7 @@ namespace MWMechanics
|
||||
&& !appliedEnchantment)
|
||||
{
|
||||
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
||||
if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f)
|
||||
if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f)
|
||||
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ namespace MWMechanics
|
||||
|
||||
saveTerm *= 1.25f * normalisedFatigue;
|
||||
|
||||
float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99());
|
||||
float x = std::max(0.f, saveTerm - Misc::Rng::roll0to99());
|
||||
|
||||
int element = ESM::MagicEffect::FireDamage;
|
||||
if (i == 1)
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef OPENMW_MECHANICS_DISEASE_H
|
||||
#define OPENMW_MECHANICS_DISEASE_H
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
@ -51,7 +51,7 @@ namespace MWMechanics
|
||||
continue;
|
||||
|
||||
int x = static_cast<int>(fDiseaseXferChance * 100 * resist);
|
||||
if (OEngine::Misc::Rng::rollDice(10000) < x)
|
||||
if (Misc::Rng::rollDice(10000) < x)
|
||||
{
|
||||
// Contracted disease!
|
||||
actor.getClass().getCreatureStats(actor).getSpells().add(it->first);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "enchanting.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwworld/manualref.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
@ -70,7 +70,7 @@ namespace MWMechanics
|
||||
|
||||
if(mSelfEnchanting)
|
||||
{
|
||||
if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99()))
|
||||
if(getEnchantChance() <= (Misc::Rng::roll0to99()))
|
||||
return false;
|
||||
|
||||
mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
|
||||
#define OPENMW_MECHANICS_LEVELLEDLIST_H
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
@ -24,7 +24,7 @@ namespace MWMechanics
|
||||
|
||||
failChance += levItem->mChanceNone;
|
||||
|
||||
if (OEngine::Misc::Rng::roll0to99() < failChance)
|
||||
if (Misc::Rng::roll0to99() < failChance)
|
||||
return std::string();
|
||||
|
||||
std::vector<std::string> candidates;
|
||||
@ -53,7 +53,7 @@ namespace MWMechanics
|
||||
}
|
||||
if (candidates.empty())
|
||||
return std::string();
|
||||
std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())];
|
||||
std::string item = candidates[Misc::Rng::rollDice(candidates.size())];
|
||||
|
||||
// Vanilla doesn't fail on nonexistent items in levelled lists
|
||||
if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item)))
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "mechanicsmanagerimp.hpp"
|
||||
#include "npcstats.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/stolenitems.hpp>
|
||||
|
||||
@ -607,7 +607,7 @@ namespace MWMechanics
|
||||
int rank = 0;
|
||||
std::string npcFaction = ptr.getClass().getPrimaryFaction(ptr);
|
||||
|
||||
Misc::StringUtils::toLower(npcFaction);
|
||||
Misc::StringUtils::lowerCaseInPlace(npcFaction);
|
||||
|
||||
if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end())
|
||||
{
|
||||
@ -741,7 +741,7 @@ namespace MWMechanics
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
int roll = OEngine::Misc::Rng::roll0to99();
|
||||
float roll = Misc::Rng::rollClosedProbability() * 100;
|
||||
|
||||
if (type == PT_Admire)
|
||||
{
|
||||
@ -1045,7 +1045,7 @@ namespace MWMechanics
|
||||
owner.first = ownerCellRef->getFaction();
|
||||
owner.second = true;
|
||||
}
|
||||
Misc::StringUtils::toLower(owner.first);
|
||||
Misc::StringUtils::lowerCaseInPlace(owner.first);
|
||||
|
||||
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
|
||||
mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count;
|
||||
@ -1399,7 +1399,7 @@ namespace MWMechanics
|
||||
|
||||
float target = x - y;
|
||||
|
||||
return (OEngine::Misc::Rng::roll0to99() >= target);
|
||||
return (Misc::Rng::roll0to99() >= target);
|
||||
}
|
||||
|
||||
void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "pickpocket.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
@ -41,7 +41,7 @@ namespace MWMechanics
|
||||
int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("iPickMaxChance")->getInt();
|
||||
|
||||
int roll = OEngine::Misc::Rng::roll0to99();
|
||||
int roll = Misc::Rng::roll0to99();
|
||||
if (t < pcSneak / iPickMinChance)
|
||||
{
|
||||
return (roll > int(pcSneak / iPickMinChance));
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
@ -48,7 +48,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
||||
|
||||
float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm;
|
||||
|
||||
int roll = OEngine::Misc::Rng::roll0to99();
|
||||
int roll = Misc::Rng::roll0to99();
|
||||
if (roll <= x)
|
||||
{
|
||||
int y = static_cast<int>(fRepairAmountMult * toolQuality * roll);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "security.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
@ -50,7 +50,7 @@ namespace MWMechanics
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock);
|
||||
if (OEngine::Misc::Rng::roll0to99() <= x)
|
||||
if (Misc::Rng::roll0to99() <= x)
|
||||
{
|
||||
lock.getClass().unlock(lock);
|
||||
resultMessage = "#{sLockSuccess}";
|
||||
@ -91,7 +91,7 @@ namespace MWMechanics
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap);
|
||||
if (OEngine::Misc::Rng::roll0to99() <= x)
|
||||
if (Misc::Rng::roll0to99() <= x)
|
||||
{
|
||||
trap.getCellRef().setTrap("");
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
@ -282,7 +282,7 @@ namespace MWMechanics
|
||||
if (castChance > 0)
|
||||
x *= 50 / castChance;
|
||||
|
||||
float roll = OEngine::Misc::Rng::rollClosedProbability() * 100;
|
||||
float roll = Misc::Rng::rollClosedProbability() * 100;
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)
|
||||
roll -= resistance;
|
||||
|
||||
@ -385,7 +385,7 @@ namespace MWMechanics
|
||||
target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude()
|
||||
: target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude();
|
||||
|
||||
if (OEngine::Misc::Rng::roll0to99() <= x)
|
||||
if (Misc::Rng::roll0to99() <= x)
|
||||
{
|
||||
// Fully resisted, show message
|
||||
if (target == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
@ -415,7 +415,7 @@ namespace MWMechanics
|
||||
if (spell && caster != target && target.getClass().isActor())
|
||||
{
|
||||
float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude();
|
||||
absorbed = (OEngine::Misc::Rng::roll0to99() < absorb);
|
||||
absorbed = (Misc::Rng::roll0to99() < absorb);
|
||||
if (absorbed)
|
||||
{
|
||||
const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Absorb");
|
||||
@ -463,7 +463,7 @@ namespace MWMechanics
|
||||
if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable))
|
||||
{
|
||||
float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude();
|
||||
bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect);
|
||||
bool isReflected = (Misc::Rng::roll0to99() < reflect);
|
||||
if (isReflected)
|
||||
{
|
||||
const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Reflect");
|
||||
@ -491,7 +491,7 @@ namespace MWMechanics
|
||||
|
||||
if (magnitudeMult > 0 && !absorbed)
|
||||
{
|
||||
float random = OEngine::Misc::Rng::rollClosedProbability();
|
||||
float random = Misc::Rng::rollClosedProbability();
|
||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
||||
magnitude *= magnitudeMult;
|
||||
|
||||
@ -823,7 +823,7 @@ namespace MWMechanics
|
||||
|
||||
// Check success
|
||||
float successChance = getSpellSuccessChance(spell, mCaster);
|
||||
if (OEngine::Misc::Rng::roll0to99() >= successChance)
|
||||
if (Misc::Rng::roll0to99() >= successChance)
|
||||
{
|
||||
if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
|
||||
@ -901,7 +901,7 @@ namespace MWMechanics
|
||||
+ 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())
|
||||
* creatureStats.getFatigueTerm();
|
||||
|
||||
int roll = OEngine::Misc::Rng::roll0to99();
|
||||
int roll = Misc::Rng::roll0to99();
|
||||
if (roll > x)
|
||||
{
|
||||
// "X has no effect on you"
|
||||
|
@ -37,7 +37,7 @@ namespace MWMechanics
|
||||
for (unsigned int i=0; i<spell->mEffects.mList.size();++i)
|
||||
{
|
||||
if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax)
|
||||
random[i] = OEngine::Misc::Rng::rollClosedProbability();
|
||||
random[i] = Misc::Rng::rollClosedProbability();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ void Animation::addAnimSource(const std::string &model)
|
||||
return;
|
||||
|
||||
std::string kfname = model;
|
||||
Misc::StringUtils::toLower(kfname);
|
||||
Misc::StringUtils::lowerCaseInPlace(kfname);
|
||||
|
||||
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
|
||||
kfname.replace(kfname.size()-4, 4, ".kf");
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
@ -103,7 +103,7 @@ void HeadAnimationTime::setEnabled(bool enabled)
|
||||
|
||||
void HeadAnimationTime::resetBlinkTimer()
|
||||
{
|
||||
mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6));
|
||||
mBlinkTimer = -(2.0f + Misc::Rng::rollDice(6));
|
||||
}
|
||||
|
||||
void HeadAnimationTime::update(float dt)
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/nifogre/ogrenifloader.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
@ -466,8 +466,8 @@ void SkyManager::updateRain(float dt)
|
||||
|
||||
// TODO: handle rain settings from Morrowind.ini
|
||||
const float rangeRandom = 100;
|
||||
float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2);
|
||||
float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2);
|
||||
float xOffs = Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2);
|
||||
float yOffs = Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2);
|
||||
|
||||
// Create a separate node to control the offset, since a node with setInheritOrientation(false) will still
|
||||
// consider the orientation of the parent node for its position, just not for its orientation
|
||||
|
@ -120,7 +120,7 @@ namespace MWScript
|
||||
const MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
|
||||
std::string current = MWBase::Environment::get().getWorld()->getCellName(cell);
|
||||
Misc::StringUtils::toLower(current);
|
||||
Misc::StringUtils::lowerCaseInPlace(current);
|
||||
|
||||
bool match = current.length()>=name.length() &&
|
||||
current.substr (0, name.length())==name;
|
||||
|
@ -114,7 +114,7 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
std::string cell = (runtime.getStringLiteral (runtime[0].mInteger));
|
||||
::Misc::StringUtils::toLower(cell);
|
||||
::Misc::StringUtils::lowerCaseInPlace(cell);
|
||||
runtime.pop();
|
||||
|
||||
// "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well."
|
||||
@ -127,7 +127,7 @@ namespace MWScript
|
||||
for (; it != cells.extEnd(); ++it)
|
||||
{
|
||||
std::string name = it->mName;
|
||||
::Misc::StringUtils::toLower(name);
|
||||
::Misc::StringUtils::lowerCaseInPlace(name);
|
||||
if (name.find(cell) != std::string::npos)
|
||||
MWBase::Environment::get().getWindowManager()->addVisitedLocation (
|
||||
it->mName,
|
||||
|
@ -542,7 +542,7 @@ namespace MWScript
|
||||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
}
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::lowerCaseInPlace(factionID);
|
||||
// Make sure this faction exists
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(factionID);
|
||||
|
||||
@ -574,7 +574,7 @@ namespace MWScript
|
||||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
}
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::lowerCaseInPlace(factionID);
|
||||
// Make sure this faction exists
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(factionID);
|
||||
|
||||
@ -613,7 +613,7 @@ namespace MWScript
|
||||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
}
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::lowerCaseInPlace(factionID);
|
||||
// Make sure this faction exists
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(factionID);
|
||||
|
||||
@ -644,7 +644,7 @@ namespace MWScript
|
||||
{
|
||||
factionID = ptr.getClass().getPrimaryFaction(ptr);
|
||||
}
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::lowerCaseInPlace(factionID);
|
||||
// Make sure this faction exists
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(factionID);
|
||||
|
||||
@ -755,7 +755,7 @@ namespace MWScript
|
||||
if (factionId.empty())
|
||||
throw std::runtime_error ("failed to determine faction");
|
||||
|
||||
::Misc::StringUtils::toLower (factionId);
|
||||
::Misc::StringUtils::lowerCaseInPlace (factionId);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
runtime.push (
|
||||
@ -790,7 +790,7 @@ namespace MWScript
|
||||
if (factionId.empty())
|
||||
throw std::runtime_error ("failed to determine faction");
|
||||
|
||||
::Misc::StringUtils::toLower (factionId);
|
||||
::Misc::StringUtils::lowerCaseInPlace (factionId);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
player.getClass().getNpcStats (player).setFactionReputation (factionId, value);
|
||||
@ -824,7 +824,7 @@ namespace MWScript
|
||||
if (factionId.empty())
|
||||
throw std::runtime_error ("failed to determine faction");
|
||||
|
||||
::Misc::StringUtils::toLower (factionId);
|
||||
::Misc::StringUtils::lowerCaseInPlace (factionId);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
player.getClass().getNpcStats (player).setFactionReputation (factionId,
|
||||
@ -869,11 +869,11 @@ namespace MWScript
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
std::string race = runtime.getStringLiteral(runtime[0].mInteger);
|
||||
::Misc::StringUtils::toLower(race);
|
||||
::Misc::StringUtils::lowerCaseInPlace(race);
|
||||
runtime.pop();
|
||||
|
||||
std::string npcRace = ptr.get<ESM::NPC>()->mBase->mRace;
|
||||
::Misc::StringUtils::toLower(npcRace);
|
||||
::Misc::StringUtils::lowerCaseInPlace(npcRace);
|
||||
|
||||
runtime.push (npcRace == race);
|
||||
}
|
||||
@ -910,7 +910,7 @@ namespace MWScript
|
||||
{
|
||||
factionID = ptr.getClass().getPrimaryFaction(ptr);
|
||||
}
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::lowerCaseInPlace(factionID);
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if(factionID!="")
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
@ -226,7 +226,7 @@ namespace MWSound
|
||||
if(!filelist.size())
|
||||
return;
|
||||
|
||||
int i = OEngine::Misc::Rng::rollDice(filelist.size());
|
||||
int i = Misc::Rng::rollDice(filelist.size());
|
||||
|
||||
// Don't play the same music track twice in a row
|
||||
if (filelist[i] == mLastPlayedMusic)
|
||||
@ -561,7 +561,7 @@ namespace MWSound
|
||||
if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound)
|
||||
return;
|
||||
|
||||
float a = OEngine::Misc::Rng::rollClosedProbability();
|
||||
float a = Misc::Rng::rollClosedProbability();
|
||||
// NOTE: We should use the "Minimum Time Between Environmental Sounds" and
|
||||
// "Maximum Time Between Environmental Sounds" fallback settings here.
|
||||
sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a);
|
||||
@ -590,7 +590,7 @@ namespace MWSound
|
||||
return;
|
||||
}
|
||||
|
||||
int r = OEngine::Misc::Rng::rollDice(total);
|
||||
int r = Misc::Rng::rollDice(total);
|
||||
int pos = 0;
|
||||
|
||||
soundIter = regn->mSoundList.begin();
|
||||
|
@ -540,7 +540,7 @@ namespace MWWorld
|
||||
|
||||
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store)
|
||||
{
|
||||
Misc::StringUtils::toLower (ref.mRefID);
|
||||
Misc::StringUtils::lowerCaseInPlace (ref.mRefID);
|
||||
|
||||
switch (store.find (ref.mRefID))
|
||||
{
|
||||
|
@ -31,6 +31,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
|
||||
|
||||
ESM::Dialogue *dialogue = 0;
|
||||
|
||||
// Land texture loading needs to use a separate internal store for each plugin.
|
||||
// We set the number of plugins here to avoid continual resizes during loading,
|
||||
// and so we can properly verify if valid plugin indices are being passed to the
|
||||
// LandTexture Store retrieval methods.
|
||||
mLandTextures.resize(esm.getGlobalReaderList()->size());
|
||||
|
||||
/// \todo Move this to somewhere else. ESMReader?
|
||||
// Cache parent esX files by tracking their indices in the global list of
|
||||
// all files/readers used by the engine. This will greaty accelerate
|
||||
|
@ -96,7 +96,7 @@ namespace MWWorld
|
||||
// This readRecord() method is used when reading a saved game.
|
||||
// Deleted globals can't appear there, so isDeleted will be ignored here.
|
||||
global.load(reader, isDeleted);
|
||||
Misc::StringUtils::toLower(global.mId);
|
||||
Misc::StringUtils::lowerCaseInPlace(global.mId);
|
||||
|
||||
Collection::iterator iter = mVariables.find (global.mId);
|
||||
if (iter!=mVariables.end())
|
||||
|
@ -366,7 +366,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||
// Roll some dice, one for each effect
|
||||
params.resize(enchantment.mEffects.mList.size());
|
||||
for (unsigned int i=0; i<params.size();++i)
|
||||
params[i].mRandom = OEngine::Misc::Rng::rollClosedProbability();
|
||||
params[i].mRandom = Misc::Rng::rollClosedProbability();
|
||||
|
||||
// Try resisting each effect
|
||||
int i=0;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
|
||||
#include "weather.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/esm/weatherstate.hpp>
|
||||
|
||||
@ -527,7 +527,7 @@ void WeatherManager::update(float duration, bool paused)
|
||||
if (mThunderSoundDelay <= 0)
|
||||
{
|
||||
// pick a random sound
|
||||
int sound = OEngine::Misc::Rng::rollDice(4);
|
||||
int sound = Misc::Rng::rollDice(4);
|
||||
std::string* soundName = NULL;
|
||||
if (sound == 0) soundName = &mThunderSoundID0;
|
||||
else if (sound == 1) soundName = &mThunderSoundID1;
|
||||
@ -543,7 +543,7 @@ void WeatherManager::update(float duration, bool paused)
|
||||
mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold );
|
||||
else
|
||||
{
|
||||
mThunderChanceNeeded = static_cast<float>(OEngine::Misc::Rng::rollDice(100));
|
||||
mThunderChanceNeeded = static_cast<float>(Misc::Rng::rollDice(100));
|
||||
mThunderChance = 0;
|
||||
mRendering->getSkyManager()->setLightningStrength( 0.f );
|
||||
}
|
||||
@ -625,7 +625,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const
|
||||
* 70% will be greater than 30 (in theory).
|
||||
*/
|
||||
|
||||
int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100
|
||||
int chance = Misc::Rng::rollDice(100) + 1; // 1..100
|
||||
int sum = 0;
|
||||
unsigned int i = 0;
|
||||
for (; i < probability.size(); ++i)
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <libs/openengine/bullet/trace.h>
|
||||
#include <libs/openengine/bullet/physic.hpp>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
@ -3145,7 +3145,7 @@ namespace MWWorld
|
||||
const ESM::CreatureLevList* list = getStore().get<ESM::CreatureLevList>().find(creatureList);
|
||||
|
||||
int iNumberCreatures = getStore().get<ESM::GameSetting>().find("iNumberCreatures")->getInt();
|
||||
int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures]
|
||||
int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures]
|
||||
|
||||
for (int i=0; i<numCreatures; ++i)
|
||||
{
|
||||
@ -3196,7 +3196,7 @@ namespace MWWorld
|
||||
|
||||
std::stringstream modelName;
|
||||
modelName << "Blood_Model_";
|
||||
int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2]
|
||||
int roll = Misc::Rng::rollDice(3); // [0, 2]
|
||||
modelName << roll;
|
||||
std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str());
|
||||
|
||||
|
@ -31,7 +31,7 @@ add_component_dir (nifoverrides
|
||||
)
|
||||
|
||||
add_component_dir (bsa
|
||||
bsa_archive bsa_file resources
|
||||
bsa_archive bsa_file resources tes4bsa_file
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
@ -70,7 +70,7 @@ add_component_dir (esmterrain
|
||||
)
|
||||
|
||||
add_component_dir (misc
|
||||
utf8stream stringops resourcehelpers
|
||||
utf8stream stringops resourcehelpers rng
|
||||
)
|
||||
|
||||
IF(NOT WIN32 AND NOT APPLE)
|
||||
@ -166,14 +166,9 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR})
|
||||
|
||||
target_link_libraries(components
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
${Boost_WAVE_LIBRARY}
|
||||
${Boost_LIBRARIES}
|
||||
${OGRE_LIBRARIES}
|
||||
${OENGINE_LIBRARY}
|
||||
${BULLET_LIBRARIES}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
@ -23,7 +23,10 @@
|
||||
|
||||
#include "bsa_archive.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <OgreFileSystem.h>
|
||||
#include <OgreArchive.h>
|
||||
@ -41,10 +44,92 @@
|
||||
#define OGRE_CONST
|
||||
#endif
|
||||
|
||||
#include <extern/BSAOpt/hash.hpp>
|
||||
#include "bsa_file.hpp"
|
||||
#include "tes4bsa_file.hpp"
|
||||
|
||||
#include "../files/constrainedfiledatastream.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Concepts from answer by Remy Lebeau
|
||||
// https://stackoverflow.com/questions/15068475/recursive-hard-disk-search-with-findfirstfile-findnextfile-c
|
||||
//
|
||||
// Also see https://msdn.microsoft.com/en-us/library/aa365200%28VS.85%29.aspx
|
||||
//
|
||||
// From 34.5 sec down to 18.5 sec on laptop with many of the data files on an external USB drive
|
||||
#if defined _WIN32 || defined _WIN64
|
||||
|
||||
#include <windows.h>
|
||||
#include <memory> // auto_ptr
|
||||
|
||||
// FIXME: not tested unicode path and filenames
|
||||
DWORD indexFiles(const std::string& rootDir, const std::string& subdir,
|
||||
std::map<std::uint64_t, std::string>& files, std::map<std::string, std::string>& index)
|
||||
{
|
||||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||
WIN32_FIND_DATA ffd;
|
||||
std::string path = rootDir + ((subdir == "") ? "" : "\\" +subdir);
|
||||
|
||||
hFind = FindFirstFile((path + "\\*").c_str(), &ffd);
|
||||
if (INVALID_HANDLE_VALUE == hFind)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
std::auto_ptr<std::vector<std::string> > subDirs;
|
||||
std::string filename;
|
||||
|
||||
do
|
||||
{
|
||||
filename = std::string(ffd.cFileName);
|
||||
|
||||
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (filename != "." && filename != "..")
|
||||
{
|
||||
if (subDirs.get() == nullptr)
|
||||
subDirs.reset(new std::vector<std::string>);
|
||||
|
||||
subDirs->push_back(filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uint64_t folderHash = GenOBHash(subdir, filename);
|
||||
|
||||
std::map<std::uint64_t, std::string>::iterator iter = files.find(folderHash);
|
||||
if (iter != files.end())
|
||||
throw std::runtime_error ("duplicate hash found");
|
||||
|
||||
files[folderHash] = path + "\\" + filename;
|
||||
|
||||
std::string entry = ((subdir == "") ? "" : subdir + "\\") + filename;
|
||||
std::replace(entry.begin(), entry.end(), '\\', '/');
|
||||
index.insert(std::make_pair (entry, path + "/" + filename));
|
||||
}
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
|
||||
DWORD dwError = GetLastError();
|
||||
if (dwError != ERROR_NO_MORE_FILES)
|
||||
return dwError;
|
||||
|
||||
if (subDirs.get() != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < subDirs->size(); ++i)
|
||||
{
|
||||
std::string dir = subDirs->at(i);
|
||||
boost::algorithm::to_lower(dir);
|
||||
// FIXME: ignoring errors for now
|
||||
dwError = indexFiles(rootDir, ((subdir == "") ? "" : subdir + "\\") + dir, files, index);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace Ogre;
|
||||
|
||||
static bool fsstrict = false;
|
||||
@ -78,6 +163,8 @@ class DirArchive: public Ogre::Archive
|
||||
|
||||
index mIndex;
|
||||
|
||||
std::map <std::uint64_t, std::string> mFiles;
|
||||
|
||||
index::const_iterator lookup_filename (std::string const & filename) const
|
||||
{
|
||||
std::string normalized = normalize_path (filename.begin (), filename.end ());
|
||||
@ -89,6 +176,10 @@ public:
|
||||
DirArchive(const String& name)
|
||||
: Archive(name, "Dir")
|
||||
{
|
||||
#if defined _WIN32 || defined _WIN64
|
||||
indexFiles(name, "", mFiles, mIndex);
|
||||
#else
|
||||
|
||||
typedef boost::filesystem::recursive_directory_iterator directory_iterator;
|
||||
|
||||
directory_iterator end;
|
||||
@ -109,6 +200,7 @@ public:
|
||||
|
||||
mIndex.insert (std::make_pair (searchable, proper));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isCaseSensitive() const { return fsstrict; }
|
||||
@ -119,6 +211,27 @@ public:
|
||||
|
||||
virtual DataStreamPtr open(const String& filename, bool readonly = true) OGRE_CONST
|
||||
{
|
||||
#if defined _WIN32 || defined _WIN64
|
||||
boost::filesystem::path p(filename);
|
||||
std::string file = p.filename().string();
|
||||
|
||||
p.remove_filename();
|
||||
std::string dir = p.string();
|
||||
boost::algorithm::to_lower(dir);
|
||||
std::replace(dir.begin(), dir.end(), '/', '\\');
|
||||
|
||||
std::uint64_t hash = GenOBHash(dir, file);
|
||||
|
||||
std::map<std::uint64_t, std::string>::const_iterator it = mFiles.find(hash);
|
||||
if (it == mFiles.end())
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "The file '" << filename << "' could not be found.";
|
||||
throw std::runtime_error (os.str());
|
||||
}
|
||||
|
||||
return openConstrainedFileDataStream (it->second.c_str());
|
||||
#else
|
||||
index::const_iterator i = lookup_filename (filename);
|
||||
|
||||
if (i == mIndex.end ())
|
||||
@ -129,6 +242,7 @@ public:
|
||||
}
|
||||
|
||||
return openConstrainedFileDataStream (i->second.c_str ());
|
||||
#endif
|
||||
}
|
||||
|
||||
StringVectorPtr list(bool recursive = true, bool dirs = false)
|
||||
@ -157,7 +271,25 @@ public:
|
||||
|
||||
bool exists(const String& filename)
|
||||
{
|
||||
#if defined _WIN32 || defined _WIN64
|
||||
boost::filesystem::path p(filename);
|
||||
std::string file = p.filename().string();
|
||||
|
||||
p.remove_filename();
|
||||
std::string dir = p.string();
|
||||
boost::algorithm::to_lower(dir);
|
||||
std::replace(dir.begin(), dir.end(), '/', '\\');
|
||||
|
||||
std::uint64_t hash = GenOBHash(dir, file);
|
||||
|
||||
std::map<std::uint64_t, std::string>::const_iterator it = mFiles.find(hash);
|
||||
if (it == mFiles.end())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return lookup_filename(filename) != mIndex.end ();
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t getModifiedTime(const String&) { return 0; }
|
||||
@ -223,6 +355,8 @@ public:
|
||||
: Archive(name, "BSA")
|
||||
{ arc.open(name); }
|
||||
|
||||
BSAArchive(const String& name, const std::string& type) : Archive(name, type) {}
|
||||
|
||||
bool isCaseSensitive() const { return false; }
|
||||
|
||||
// The archive is loaded in the constructor, and never unloaded.
|
||||
@ -241,7 +375,7 @@ public:
|
||||
return narc->getFile(filename.c_str());
|
||||
}
|
||||
|
||||
bool exists(const String& filename) {
|
||||
virtual bool exists(const String& filename) {
|
||||
return arc.exists(filename.c_str());
|
||||
}
|
||||
|
||||
@ -259,7 +393,7 @@ public:
|
||||
return findFileInfo ("*", recursive, dirs);
|
||||
}
|
||||
|
||||
StringVectorPtr find(const String& pattern, bool recursive = true,
|
||||
virtual StringVectorPtr find(const String& pattern, bool recursive = true,
|
||||
bool dirs = false)
|
||||
{
|
||||
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
|
||||
@ -306,6 +440,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TES4BSAArchive : public BSAArchive
|
||||
{
|
||||
Bsa::TES4BSAFile arc;
|
||||
|
||||
public:
|
||||
TES4BSAArchive::TES4BSAArchive(const String& name) : BSAArchive(name, "TES4BSA") { arc.open(name); }
|
||||
|
||||
virtual DataStreamPtr open(const String& filename, bool readonly = true)
|
||||
{
|
||||
return arc.getFile(filename);
|
||||
}
|
||||
|
||||
virtual bool exists(const String& filename)
|
||||
{
|
||||
return arc.exists(filename);
|
||||
}
|
||||
};
|
||||
|
||||
// An archive factory for BSA archives
|
||||
class BSAArchiveFactory : public ArchiveFactory
|
||||
{
|
||||
@ -351,9 +503,32 @@ public:
|
||||
void destroyInstance( Archive* arch) { delete arch; }
|
||||
};
|
||||
|
||||
class TES4BSAArchiveFactory : public ArchiveFactory
|
||||
{
|
||||
public:
|
||||
const String& getType() const
|
||||
{
|
||||
static String name = "TES4BSA";
|
||||
return name;
|
||||
}
|
||||
|
||||
Archive *createInstance( const String& name )
|
||||
{
|
||||
return new TES4BSAArchive(name);
|
||||
}
|
||||
|
||||
virtual Archive* createInstance(const String& name, bool readOnly)
|
||||
{
|
||||
return new TES4BSAArchive(name);
|
||||
}
|
||||
|
||||
void destroyInstance( Archive* arch) { delete arch; }
|
||||
};
|
||||
|
||||
|
||||
static bool init = false;
|
||||
static bool init2 = false;
|
||||
static bool init3 = false;
|
||||
|
||||
static void insertBSAFactory()
|
||||
{
|
||||
@ -364,6 +539,15 @@ static void insertBSAFactory()
|
||||
}
|
||||
}
|
||||
|
||||
static void insertTES4BSAFactory()
|
||||
{
|
||||
if(!init3)
|
||||
{
|
||||
ArchiveManager::getSingleton().addArchiveFactory( new TES4BSAArchiveFactory );
|
||||
init3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void insertDirFactory()
|
||||
{
|
||||
if(!init2)
|
||||
@ -386,6 +570,13 @@ void addBSA(const std::string& name, const std::string& group)
|
||||
addResourceLocation(name, "BSA", group, true);
|
||||
}
|
||||
|
||||
void addTES4BSA(const std::string& name, const std::string& group)
|
||||
{
|
||||
insertTES4BSAFactory();
|
||||
ResourceGroupManager::getSingleton().
|
||||
addResourceLocation(name, "TES4BSA", group, true);
|
||||
}
|
||||
|
||||
void addDir(const std::string& name, const bool& fs, const std::string& group)
|
||||
{
|
||||
fsstrict = fs;
|
||||
|
@ -33,6 +33,7 @@ namespace Bsa
|
||||
/// Add the given BSA file as an input archive in the Ogre resource
|
||||
/// system.
|
||||
void addBSA(const std::string& file, const std::string& group="General");
|
||||
void addTES4BSA(const std::string& file, const std::string& group="General");
|
||||
void addDir(const std::string& file, const bool& fs, const std::string& group="General");
|
||||
|
||||
}
|
||||
|
@ -27,9 +27,41 @@
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "../files/constrainedfiledatastream.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
// see: http://en.uesp.net/wiki/Tes3Mod:BSA_File_Format
|
||||
std::uint64_t getHash(const char *name)
|
||||
{
|
||||
unsigned int len = (unsigned int)strlen(name);
|
||||
std::uint64_t hash;
|
||||
|
||||
unsigned l = (len>>1);
|
||||
unsigned sum, off, temp, i, n, hash1;
|
||||
|
||||
for(sum = off = i = 0; i < l; i++) {
|
||||
sum ^= (((unsigned)(name[i]))<<(off&0x1F));
|
||||
off += 8;
|
||||
}
|
||||
hash1 = sum;
|
||||
|
||||
for(sum = off = 0; i < len; i++) {
|
||||
temp = (((unsigned)(name[i]))<<(off&0x1F));
|
||||
sum ^= temp;
|
||||
n = temp & 0x1F;
|
||||
sum = (sum << (32-n)) | (sum >> n); // binary "rotate right"
|
||||
off += 8;
|
||||
}
|
||||
hash = sum;
|
||||
hash <<= 32;
|
||||
hash += hash1;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
using namespace Bsa;
|
||||
|
||||
@ -143,7 +175,14 @@ void BSAFile::readHeader()
|
||||
fail("Archive contains offsets outside itself");
|
||||
|
||||
// Add the file name to the lookup
|
||||
lookup[fs.name] = i;
|
||||
//lookup[fs.name] = i;
|
||||
}
|
||||
|
||||
std::uint64_t hash;
|
||||
for (size_t i = 0; i < filenum; ++i)
|
||||
{
|
||||
input.read(reinterpret_cast<char*>(&hash), 8);
|
||||
mFiles[hash] = files[i];
|
||||
}
|
||||
|
||||
isLoaded = true;
|
||||
@ -152,13 +191,14 @@ void BSAFile::readHeader()
|
||||
/// Get the index of a given file name, or -1 if not found
|
||||
int BSAFile::getIndex(const char *str) const
|
||||
{
|
||||
Lookup::const_iterator it = lookup.find(str);
|
||||
if(it == lookup.end())
|
||||
std::string name(str);
|
||||
boost::algorithm::to_lower(name);
|
||||
std::uint64_t hash = getHash(name.c_str());
|
||||
std::map<std::uint64_t, FileStruct>::const_iterator iter = mFiles.find(hash);
|
||||
if (iter != mFiles.end())
|
||||
return 0; // NOTE: this is a bit of a hack, exists() only checks for '-1'
|
||||
else
|
||||
return -1;
|
||||
|
||||
int res = it->second;
|
||||
assert(res >= 0 && (size_t)res < files.size());
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Open an archive file.
|
||||
@ -171,10 +211,15 @@ void BSAFile::open(const string &file)
|
||||
Ogre::DataStreamPtr BSAFile::getFile(const char *file)
|
||||
{
|
||||
assert(file);
|
||||
int i = getIndex(file);
|
||||
if(i == -1)
|
||||
fail("File not found: " + string(file));
|
||||
|
||||
const FileStruct &fs = files[i];
|
||||
return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize);
|
||||
std::string name(file);
|
||||
boost::algorithm::to_lower(name);
|
||||
std::uint64_t hash = getHash(name.c_str());
|
||||
std::map<std::uint64_t, FileStruct>::const_iterator it = mFiles.find(hash);
|
||||
if (it != mFiles.end())
|
||||
{
|
||||
const FileStruct &fs = it->second;
|
||||
return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize);
|
||||
}
|
||||
fail("File not found: " + string(file));
|
||||
}
|
||||
|
@ -82,6 +82,8 @@ private:
|
||||
typedef std::map<const char*, int, iltstr> Lookup;
|
||||
Lookup lookup;
|
||||
|
||||
std::map<std::uint64_t, FileStruct> mFiles;
|
||||
|
||||
/// Error handling
|
||||
void fail(const std::string &msg);
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "bsa_archive.hpp"
|
||||
|
||||
void Bsa::registerResources (const Files::Collections& collections,
|
||||
const std::vector<std::string>& archives, bool useLooseFiles, bool fsStrict)
|
||||
const std::vector<std::string>& archives, bool useLooseFiles, bool fsStrict, bool isTes4)
|
||||
{
|
||||
const Files::PathContainer& dataDirs = collections.getPaths();
|
||||
|
||||
@ -34,13 +34,16 @@ void Bsa::registerResources (const Files::Collections& collections,
|
||||
if (collections.doesExist(*archive))
|
||||
{
|
||||
// Last BSA has the highest priority
|
||||
std::string groupName = "DataBSA" + Ogre::StringConverter::toString(archives.size()-i, 8, '0');
|
||||
std::string groupName = (isTes4 ? "TES4BSA" : "DataBSA") + Ogre::StringConverter::toString(archives.size()-i, 8, '0');
|
||||
|
||||
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName);
|
||||
|
||||
const std::string archivePath = collections.getPath(*archive).string();
|
||||
std::cout << "Adding BSA archive " << archivePath << std::endl;
|
||||
Bsa::addBSA(archivePath, groupName);
|
||||
if (!isTes4)
|
||||
Bsa::addBSA(archivePath, groupName);
|
||||
else
|
||||
Bsa::addTES4BSA(archivePath, groupName);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
|
@ -9,7 +9,7 @@
|
||||
namespace Bsa
|
||||
{
|
||||
void registerResources (const Files::Collections& collections,
|
||||
const std::vector<std::string>& archives, bool useLooseFiles, bool fsStrict);
|
||||
const std::vector<std::string>& archives, bool useLooseFiles, bool fsStrict, bool isTes4=false);
|
||||
///< Register resources directories and archives as OGRE resources groups
|
||||
}
|
||||
|
||||
|
339
components/bsa/tes4bsa_file.cpp
Normal file
339
components/bsa/tes4bsa_file.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (bsa_file.cpp) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
TES4 stuff added by cc9cii 2018
|
||||
|
||||
*/
|
||||
#include "tes4bsa_file.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <extern/BSAOpt/hash.hpp> // see: http://en.uesp.net/wiki/Tes4Mod:Hash_Calculation
|
||||
|
||||
#undef TEST_UNIQUE_HASH
|
||||
|
||||
namespace
|
||||
{
|
||||
void getBZString(std::string& str, boost::filesystem::ifstream& filestream)
|
||||
{
|
||||
char size = 0;
|
||||
filestream.read(&size, 1);
|
||||
|
||||
boost::scoped_array<char> buf(new char[size]);
|
||||
filestream.read(buf.get(), size);
|
||||
|
||||
if (buf[size - 1] != 0)
|
||||
str.assign(buf.get(), size);
|
||||
else
|
||||
str.assign(buf.get(), size - 1); // don't copy null terminator
|
||||
assert((size_t)size-1 == str.size() && "getBZString string size mismatch");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Bsa;
|
||||
|
||||
|
||||
/// Error handling
|
||||
void TES4BSAFile::fail(const std::string& msg)
|
||||
{
|
||||
throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + mFilename);
|
||||
}
|
||||
|
||||
/// Read header information from the input source
|
||||
void TES4BSAFile::readHeader()
|
||||
{
|
||||
assert(!isLoaded);
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
bfs::ifstream input(bfs::path(mFilename), std::ios_base::binary);
|
||||
|
||||
// Total archive size
|
||||
std::streamoff fsize = 0;
|
||||
if(input.seekg(0, std::ios_base::end))
|
||||
{
|
||||
fsize = input.tellg();
|
||||
input.seekg(0);
|
||||
}
|
||||
|
||||
if(fsize < 36) // header is 36 bytes
|
||||
fail("File too small to be a valid BSA archive");
|
||||
|
||||
// Get essential header numbers
|
||||
//size_t dirsize, filenum;
|
||||
std::uint32_t archiveFlags, folderCount, fileCount, totalFileNameLength;
|
||||
{
|
||||
// First 36 bytes
|
||||
std::uint32_t header[9];
|
||||
|
||||
input.read(reinterpret_cast<char*>(header), 36);
|
||||
|
||||
if(header[0] != 0x00415342 /*"BSA\x00"*/ || (header[1] != 0x67 /*TES4*/ && header[1] != 0x68 /*TES5*/))
|
||||
fail("Unrecognized TES4 BSA header");
|
||||
|
||||
// header[2] is offset, should be 36 = 0x24 which is the size of the header
|
||||
|
||||
// Oblivion - Meshes.bsa
|
||||
//
|
||||
// 0111 1000 0111 = 0x0787
|
||||
// ^^^ ^ ^^^
|
||||
// ||| | ||+-- has names for dirs (mandatory?)
|
||||
// ||| | |+--- has names for files (mandatory?)
|
||||
// ||| | +---- files are compressed by default
|
||||
// ||| |
|
||||
// ||| +---------- unknown (TES5: retain strings during startup)
|
||||
// ||+------------ unknown (TES5: embedded file names)
|
||||
// |+------------- unknown
|
||||
// +-------------- unknown
|
||||
//
|
||||
archiveFlags = header[3];
|
||||
folderCount = header[4];
|
||||
fileCount = header[5];
|
||||
//totalFolderNameLength = header[6];
|
||||
totalFileNameLength = header[7];
|
||||
//fileFlags = header[8]; // FIXME: an opportunity to optimize here
|
||||
|
||||
mCompressedByDefault = (archiveFlags & 0x4) != 0;
|
||||
mEmbeddedFileNames = header[1] == 0x68 /*TES5*/ && (archiveFlags & 0x100) != 0;
|
||||
}
|
||||
|
||||
// TODO: more checks for BSA file corruption
|
||||
|
||||
// folder records
|
||||
std::uint64_t hash;
|
||||
FolderRecord fr;
|
||||
for (std::uint32_t i = 0; i < folderCount; ++i)
|
||||
{
|
||||
input.read(reinterpret_cast<char*>(&hash), 8);
|
||||
input.read(reinterpret_cast<char*>(&fr.count), 4); // not sure purpose of count
|
||||
input.read(reinterpret_cast<char*>(&fr.offset), 4); // not sure purpose of offset
|
||||
|
||||
std::map<std::uint64_t, FolderRecord>::const_iterator lb = mFolders.lower_bound(hash);
|
||||
if (lb != mFolders.end() && !(mFolders.key_comp()(hash, lb->first)))
|
||||
fail("Archive found duplicate folder name hash");
|
||||
else
|
||||
mFolders.insert(lb, std::pair<std::uint64_t, FolderRecord>(hash, fr));
|
||||
}
|
||||
|
||||
// file record blocks
|
||||
std::uint64_t fileHash;
|
||||
FileRecord file;
|
||||
|
||||
std::string folder("");
|
||||
std::uint64_t folderHash;
|
||||
if ((archiveFlags & 0x1) == 0)
|
||||
folderCount = 1; // TODO: not tested
|
||||
|
||||
for (std::uint32_t i = 0; i < folderCount; ++i)
|
||||
{
|
||||
if ((archiveFlags & 0x1) != 0)
|
||||
getBZString(folder, input);
|
||||
|
||||
folderHash = GenOBHash(folder, std::string(""));
|
||||
|
||||
std::map<std::uint64_t, FolderRecord>::iterator iter = mFolders.find(folderHash);
|
||||
if (iter == mFolders.end())
|
||||
fail("Archive folder name hash not found");
|
||||
|
||||
for (std::uint32_t j = 0; j < iter->second.count; ++j)
|
||||
{
|
||||
input.read(reinterpret_cast<char*>(&fileHash), 8);
|
||||
input.read(reinterpret_cast<char*>(&file.size), 4);
|
||||
input.read(reinterpret_cast<char*>(&file.offset), 4);
|
||||
|
||||
std::map<std::uint64_t, FileRecord>::const_iterator lb = iter->second.files.lower_bound(fileHash);
|
||||
if (lb != iter->second.files.end() && !(iter->second.files.key_comp()(fileHash, lb->first)))
|
||||
fail("Archive found duplicate file name hash");
|
||||
|
||||
iter->second.files.insert(lb, std::pair<std::uint64_t, FileRecord>(fileHash, file));
|
||||
}
|
||||
}
|
||||
|
||||
// file record blocks
|
||||
if ((archiveFlags & 0x2) != 0)
|
||||
{
|
||||
mStringBuf.resize(totalFileNameLength);
|
||||
input.read(&mStringBuf[0], mStringBuf.size()); // TODO: maybe useful in building a lookup map?
|
||||
}
|
||||
|
||||
// TODO: more checks for BSA file corruption
|
||||
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
TES4BSAFile::FileRecord TES4BSAFile::getFileRecord(const std::string& str) const
|
||||
{
|
||||
boost::filesystem::path p(str);
|
||||
std::string stem = p.stem().string();
|
||||
std::string ext = p.extension().string();
|
||||
std::string filename = p.filename().string();
|
||||
p.remove_filename();
|
||||
|
||||
std::string folder = p.string();
|
||||
// GenOBHash already converts to lowercase and replaces file separators but not for path
|
||||
boost::algorithm::to_lower(folder);
|
||||
std::replace(folder.begin(), folder.end(), '/', '\\');
|
||||
|
||||
std::uint64_t folderHash = GenOBHash(folder, std::string(""));
|
||||
|
||||
std::map<std::uint64_t, FolderRecord>::const_iterator it = mFolders.find(folderHash);
|
||||
if (it == mFolders.end())
|
||||
return FileRecord(); // folder not found, return default which has offset of -1
|
||||
|
||||
boost::algorithm::to_lower(stem);
|
||||
boost::algorithm::to_lower(ext);
|
||||
std::uint64_t fileHash = GenOBHashPair(stem, ext);
|
||||
std::map<std::uint64_t, FileRecord>::const_iterator iter = it->second.files.find(fileHash);
|
||||
if (iter == it->second.files.end())
|
||||
return FileRecord(); // file not found, return default which has offset of -1
|
||||
|
||||
// cache for next time
|
||||
std::uint64_t hash = GenOBHash(folder, filename);
|
||||
|
||||
#if defined (TEST_UNIQUE_HASH)
|
||||
FileList::const_iterator lb = mFiles.lower_bound(hash);
|
||||
if (lb != mFiles.end() && !(mFiles.key_comp()(hash, lb->first)))
|
||||
{
|
||||
// found, check if same filename
|
||||
if (lb->second.fileName == str)
|
||||
return iter->second; // same name, should not have got here!!
|
||||
else
|
||||
{
|
||||
// different filename, hash is not unique!
|
||||
std::cerr << "BSA hash collision: " << str << std::hex << "0x" << hash << std::endl;
|
||||
|
||||
return iter->second; // return without cashing
|
||||
}
|
||||
}
|
||||
|
||||
// not found, cache for later
|
||||
const_cast<FileList&>(mFiles).insert(lb, std::pair<std::uint64_t, FileRecord>(hash, iter->second));
|
||||
const_cast<FileList&>(mFiles)[hash].fileName = str;
|
||||
#else
|
||||
const_cast<FileList&>(mFiles)[hash] = iter->second; // NOTE: const hack
|
||||
#endif
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool TES4BSAFile::exists(const std::string& str) const
|
||||
{
|
||||
// check cache first
|
||||
boost::filesystem::path p(str);
|
||||
std::string filename = p.filename().string();
|
||||
p.remove_filename();
|
||||
|
||||
std::string folder = p.string();
|
||||
// GenOBHash already converts to lowercase and replaces file separators but not for path
|
||||
boost::algorithm::to_lower(folder);
|
||||
std::replace(folder.begin(), folder.end(), '/', '\\');
|
||||
|
||||
std::uint64_t hash = GenOBHash(folder, filename);
|
||||
|
||||
std::map<std::uint64_t, FileRecord>::const_iterator it = mFiles.find(hash);
|
||||
#if defined (TEST_UNIQUE_HASH)
|
||||
if (it != mFiles.end() && it->second.fileName == str)
|
||||
#else
|
||||
if (it != mFiles.end())
|
||||
#endif
|
||||
return true;
|
||||
else
|
||||
return getFileRecord(str).offset != -1;
|
||||
}
|
||||
|
||||
void TES4BSAFile::open(const std::string& file)
|
||||
{
|
||||
mFilename = file;
|
||||
readHeader();
|
||||
}
|
||||
|
||||
Ogre::DataStreamPtr TES4BSAFile::getFile(const std::string& file)
|
||||
{
|
||||
assert(file);
|
||||
|
||||
FileRecord fileRec = getFileRecord(file);
|
||||
if(fileRec.offset == -1)
|
||||
fail("File not found: " + std::string(file));
|
||||
|
||||
boost::filesystem::ifstream input(boost::filesystem::path(mFilename), std::ios_base::binary);
|
||||
input.seekg(fileRec.offset);
|
||||
|
||||
std::string fullPath;
|
||||
if (mEmbeddedFileNames)
|
||||
getBZString(fullPath, input); // TODO: maybe cache the hash and/or offset of frequently used ones?
|
||||
|
||||
if (( mCompressedByDefault && (fileRec.size & (1<<30)) == 0)
|
||||
||
|
||||
(!mCompressedByDefault && (fileRec.size & (1<<30)) != 0))
|
||||
{
|
||||
std::uint32_t bufSize = 0;
|
||||
boost::scoped_array<unsigned char> inBuf;
|
||||
inBuf.reset(new unsigned char[fileRec.size-4]);
|
||||
input.read(reinterpret_cast<char*>(&bufSize), 4);
|
||||
input.read(reinterpret_cast<char*>(inBuf.get()), fileRec.size-4);
|
||||
Ogre::MemoryDataStream *outBuf = new Ogre::MemoryDataStream(bufSize);
|
||||
Ogre::SharedPtr<Ogre::DataStream> streamPtr(outBuf);
|
||||
|
||||
int ret;
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = bufSize;
|
||||
strm.next_in = inBuf.get();
|
||||
ret = inflateInit(&strm);
|
||||
if (ret != Z_OK)
|
||||
throw std::runtime_error("TES4BSAFile::getFile - inflateInit failed");
|
||||
|
||||
strm.avail_out = bufSize;
|
||||
strm.next_out = outBuf->getPtr();
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
assert(ret != Z_STREAM_ERROR && "TES4BSAFile::getFile - inflate - state clobbered");
|
||||
switch (ret)
|
||||
{
|
||||
case Z_NEED_DICT:
|
||||
ret = Z_DATA_ERROR; /* and fall through */
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&strm);
|
||||
throw std::runtime_error("TES4BSAFile::getFile - inflate failed");
|
||||
}
|
||||
assert(ret == Z_OK || ret == Z_STREAM_END);
|
||||
inflateEnd(&strm);
|
||||
|
||||
return streamPtr;
|
||||
}
|
||||
else // not compressed TODO: not tested
|
||||
{
|
||||
Ogre::MemoryDataStream *outBuf = new Ogre::MemoryDataStream(fileRec.size);
|
||||
Ogre::SharedPtr<Ogre::DataStream> streamPtr(outBuf);
|
||||
input.read(reinterpret_cast<char*>(outBuf->getPtr()), fileRec.size);
|
||||
|
||||
return streamPtr;
|
||||
}
|
||||
}
|
103
components/bsa/tes4bsa_file.hpp
Normal file
103
components/bsa/tes4bsa_file.hpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (bsa_file.h) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
TES4 stuff added by cc9cii 2018
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BSA_TES4BSA_FILE_H
|
||||
#define BSA_TES4BSA_FILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <OgreDataStream.h>
|
||||
|
||||
|
||||
namespace Bsa
|
||||
{
|
||||
class TES4BSAFile
|
||||
{
|
||||
public:
|
||||
struct FileRecord
|
||||
{
|
||||
std::uint32_t size;
|
||||
std::uint32_t offset;
|
||||
|
||||
std::string fileName; // NOTE: for testing hash collision only, see TEST_UNIQUE_HASH
|
||||
|
||||
FileRecord() : size(0), offset(-1) {}
|
||||
};
|
||||
|
||||
private:
|
||||
/// Filenames string buffer
|
||||
std::vector<char> mStringBuf;
|
||||
|
||||
/// True when an archive has been loaded
|
||||
bool isLoaded;
|
||||
|
||||
bool mCompressedByDefault;
|
||||
bool mEmbeddedFileNames;
|
||||
|
||||
std::map<std::uint64_t, FileRecord> mFiles;
|
||||
typedef std::map<std::uint64_t, FileRecord> FileList;
|
||||
|
||||
struct FolderRecord
|
||||
{
|
||||
std::uint32_t count;
|
||||
std::uint32_t offset;
|
||||
std::map<std::uint64_t, FileRecord> files;
|
||||
};
|
||||
std::map<std::uint64_t, FolderRecord> mFolders;
|
||||
|
||||
FileRecord getFileRecord(const std::string& str) const;
|
||||
|
||||
/// Used for error messages and getting files
|
||||
std::string mFilename;
|
||||
|
||||
/// Error handling
|
||||
void fail(const std::string &msg);
|
||||
|
||||
/// Read header information from the input source
|
||||
void readHeader();
|
||||
|
||||
public:
|
||||
TES4BSAFile()
|
||||
: isLoaded(false), mCompressedByDefault(false), mEmbeddedFileNames(false)
|
||||
{ }
|
||||
|
||||
/// Open an archive file.
|
||||
void open(const std::string &file);
|
||||
|
||||
/// Check if a file exists
|
||||
bool exists(const std::string& file) const;
|
||||
|
||||
Ogre::DataStreamPtr getFile(const std::string& file);
|
||||
|
||||
/// Get a list of all files
|
||||
const FileList &getList() const // FIXME
|
||||
{ return mFiles; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -243,11 +243,14 @@ namespace Gui
|
||||
std::string textureName = name;
|
||||
Ogre::Image image;
|
||||
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
|
||||
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
width, height, 0, Ogre::PF_BYTE_RGBA);
|
||||
texture->loadImage(image);
|
||||
if (!Ogre::TextureManager::getSingleton().resourceExists(textureName))
|
||||
{
|
||||
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
width, height, 0, Ogre::PF_BYTE_RGBA);
|
||||
texture->loadImage(image);
|
||||
}
|
||||
|
||||
if (exportToFile)
|
||||
image.save(resourceName + ".png");
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "runtime.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
@ -148,7 +148,7 @@ namespace Interpreter
|
||||
throw std::runtime_error (
|
||||
"random: argument out of range (Don't be so negative!)");
|
||||
|
||||
Type_Integer value = OEngine::Misc::Rng::rollDice(limit); // [o, limit)
|
||||
Type_Integer value = Misc::Rng::rollDice(limit); // [o, limit)
|
||||
|
||||
runtime[0].mInteger = value;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev
|
||||
std::string prefix2 = topLevelDirectory + '/';
|
||||
|
||||
std::string correctedPath = resPath;
|
||||
Misc::StringUtils::toLower(correctedPath);
|
||||
Misc::StringUtils::lowerCaseInPlace(correctedPath);
|
||||
|
||||
// Apparently, leading separators are allowed
|
||||
while (correctedPath.size() && (correctedPath[0] == '/' || correctedPath[0] == '\\'))
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Misc {
|
||||
namespace Misc
|
||||
{
|
||||
|
||||
void Rng::init()
|
||||
{
|
||||
@ -26,4 +26,3 @@ namespace Misc {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
#ifndef MISC_RNG_H
|
||||
#define MISC_RNG_H
|
||||
#ifndef OPENMW_COMPONENTS_MISC_RNG_H
|
||||
#define OPENMW_COMPONENTS_MISC_RNG_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Misc
|
||||
{
|
||||
|
||||
@ -30,7 +29,6 @@ public:
|
||||
static int roll0to99() { return rollDice(100); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -70,17 +70,17 @@ public:
|
||||
}
|
||||
|
||||
/// Transforms input string to lower case w/o copy
|
||||
static std::string &toLower(std::string &inout) {
|
||||
static void lowerCaseInPlace(std::string &inout) {
|
||||
for (unsigned int i=0; i<inout.size(); ++i)
|
||||
inout[i] = tolower(inout[i]);
|
||||
return inout;
|
||||
}
|
||||
|
||||
/// Returns lower case copy of input string
|
||||
static std::string lowerCase(const std::string &in)
|
||||
{
|
||||
std::string out = in;
|
||||
return toLower(out);
|
||||
lowerCaseInPlace(out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,7 +135,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||
// FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused
|
||||
mControlledNodes.clear();
|
||||
std::string kfname = mResourceName.substr(0, mResourceName.length()-7);
|
||||
Misc::StringUtils::toLower(kfname);
|
||||
Misc::StringUtils::lowerCaseInPlace(kfname);
|
||||
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
|
||||
kfname.replace(kfname.size()-4, 4, ".kf");
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname))
|
||||
|
@ -711,7 +711,7 @@ private:
|
||||
std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex);
|
||||
if(shape->name.length() > 0)
|
||||
fullname += "@shape="+shape->name;
|
||||
Misc::StringUtils::toLower(fullname);
|
||||
Misc::StringUtils::lowerCaseInPlace(fullname);
|
||||
|
||||
Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton();
|
||||
if(meshMgr.getByName(fullname).isNull())
|
||||
@ -944,7 +944,7 @@ private:
|
||||
std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex);
|
||||
if(partnode->name.length() > 0)
|
||||
fullname += "@type="+partnode->name;
|
||||
Misc::StringUtils::toLower(fullname);
|
||||
Misc::StringUtils::lowerCaseInPlace(fullname);
|
||||
|
||||
Ogre::ParticleSystem *partsys = sceneNode->getCreator()->createParticleSystem();
|
||||
|
||||
@ -1172,7 +1172,7 @@ private:
|
||||
nextpos = std::distance(str.begin(), ++last);
|
||||
}
|
||||
std::string result = str.substr(pos, nextpos-pos);
|
||||
textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result)));
|
||||
textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::lowerCase(result)));
|
||||
|
||||
pos = nextpos;
|
||||
}
|
||||
@ -1377,7 +1377,7 @@ ObjectScenePtr Loader::createObjects(Ogre::SceneNode *parentNode, std::string na
|
||||
{
|
||||
ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator()));
|
||||
|
||||
Misc::StringUtils::toLower(name);
|
||||
Misc::StringUtils::lowerCaseInPlace(name);
|
||||
NIFObjectLoader::load(parentNode, scene, name, group);
|
||||
|
||||
for(size_t i = 0;i < scene->mEntities.size();i++)
|
||||
@ -1399,7 +1399,7 @@ ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bo
|
||||
{
|
||||
ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator()));
|
||||
|
||||
Misc::StringUtils::toLower(name);
|
||||
Misc::StringUtils::lowerCaseInPlace(name);
|
||||
NIFObjectLoader::load(parentNode, scene, name, group);
|
||||
|
||||
bool isskinned = false;
|
||||
@ -1422,8 +1422,8 @@ ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bo
|
||||
// accepts anything named "filter*" or "tri filter*"
|
||||
std::string filter = "@shape=tri "+bonefilter;
|
||||
std::string filter2 = "@shape="+bonefilter;
|
||||
Misc::StringUtils::toLower(filter);
|
||||
Misc::StringUtils::toLower(filter2);
|
||||
Misc::StringUtils::lowerCaseInPlace(filter);
|
||||
Misc::StringUtils::lowerCaseInPlace(filter2);
|
||||
for(size_t i = 0;i < scene->mEntities.size();i++)
|
||||
{
|
||||
Ogre::Entity *entity = scene->mEntities[i];
|
||||
@ -1465,7 +1465,7 @@ ObjectScenePtr Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string
|
||||
{
|
||||
ObjectScenePtr scene = ObjectScenePtr (new ObjectScene(parentNode->getCreator()));
|
||||
|
||||
Misc::StringUtils::toLower(name);
|
||||
Misc::StringUtils::lowerCaseInPlace(name);
|
||||
NIFObjectLoader::load(parentNode, scene, name, group, 0xC0000000);
|
||||
|
||||
if(scene->mSkelBase)
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreSceneManager.h>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
/* FIXME: "Nif" isn't really an appropriate emitter name. */
|
||||
class NifEmitter : public Ogre::ParticleEmitter
|
||||
@ -173,7 +173,7 @@ public:
|
||||
Ogre::Real& timeToLive = particle->timeToLive;
|
||||
#endif
|
||||
|
||||
Ogre::Node* emitterBone = mEmitterBones.at(OEngine::Misc::Rng::rollDice(mEmitterBones.size()));
|
||||
Ogre::Node* emitterBone = mEmitterBones.at(Misc::Rng::rollDice(mEmitterBones.size()));
|
||||
|
||||
position = xOff + yOff + zOff +
|
||||
mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition()
|
||||
|
129
components/sceneutil/lightcontroller.cpp
Normal file
129
components/sceneutil/lightcontroller.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
#include "lightcontroller.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <osg/NodeVisitor>
|
||||
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
float pulseAmplitude(float time)
|
||||
{
|
||||
return std::sin(time);
|
||||
}
|
||||
|
||||
float flickerAmplitude(float time)
|
||||
{
|
||||
static const float fb = 1.17024f;
|
||||
static const float f[3] = { 1.5708f, 4.18774f, 5.19934f };
|
||||
static const float o[3] = { 0.804248f, 2.11115f, 3.46832f };
|
||||
static const float m[3] = { 1.0f, 0.785f, 0.876f };
|
||||
static const float s = 0.394f;
|
||||
|
||||
float v = 0.0f;
|
||||
for(int i = 0;i < 3;++i)
|
||||
v += std::sin(fb*time*f[i] + o[1])*m[i];
|
||||
return v * s;
|
||||
}
|
||||
|
||||
float flickerFrequency(float phase)
|
||||
{
|
||||
static const float fa = 0.785398f;
|
||||
static const float tdo = 0.94f;
|
||||
static const float tdm = 2.48f;
|
||||
|
||||
return tdo + tdm*std::sin(fa * phase);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
|
||||
LightController::LightController()
|
||||
: mType(LT_Normal)
|
||||
, mPhase((Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f)
|
||||
, mLastTime(0.0)
|
||||
, mDeltaCount(0.f)
|
||||
, mDirection(1.f)
|
||||
{
|
||||
}
|
||||
|
||||
void LightController::setType(LightController::LightType type)
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
double time = nv->getFrameStamp()->getSimulationTime();
|
||||
if (time == mLastTime)
|
||||
return;
|
||||
|
||||
float dt = static_cast<float>(time - mLastTime);
|
||||
mLastTime = time;
|
||||
|
||||
float brightness = 1.0f;
|
||||
float cycle_time;
|
||||
float time_distortion;
|
||||
|
||||
const float pi = 3.14159265359;
|
||||
|
||||
if(mType == LT_Pulse || mType == LT_PulseSlow)
|
||||
{
|
||||
cycle_time = 2.0f * pi;
|
||||
time_distortion = 20.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const float fa = 0.785398f;
|
||||
static const float phase_wavelength = 120.0f * pi / fa;
|
||||
|
||||
cycle_time = 500.0f;
|
||||
mPhase = std::fmod(mPhase + dt, phase_wavelength);
|
||||
time_distortion = flickerFrequency(mPhase);
|
||||
}
|
||||
|
||||
mDeltaCount += mDirection*dt*time_distortion;
|
||||
if(mDirection > 0 && mDeltaCount > +cycle_time)
|
||||
{
|
||||
mDirection = -1.0f;
|
||||
mDeltaCount = 2.0f*cycle_time - mDeltaCount;
|
||||
}
|
||||
if(mDirection < 0 && mDeltaCount < -cycle_time)
|
||||
{
|
||||
mDirection = +1.0f;
|
||||
mDeltaCount = -2.0f*cycle_time - mDeltaCount;
|
||||
}
|
||||
|
||||
static const float fast = 4.0f/1.0f;
|
||||
static const float slow = 1.0f/1.0f;
|
||||
|
||||
// These formulas are just guesswork, but they work pretty well
|
||||
if(mType == LT_Normal)
|
||||
{
|
||||
// Less than 1/255 light modifier for a constant light:
|
||||
brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f;
|
||||
}
|
||||
else if(mType == LT_Flicker)
|
||||
brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f;
|
||||
else if(mType == LT_FlickerSlow)
|
||||
brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f;
|
||||
else if(mType == LT_Pulse)
|
||||
brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f;
|
||||
else if(mType == LT_PulseSlow)
|
||||
brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f;
|
||||
|
||||
static_cast<SceneUtil::LightSource*>(node)->getLight()->setDiffuse(mDiffuseColor * brightness);
|
||||
}
|
||||
|
||||
void LightController::setDiffuse(osg::Vec4f color)
|
||||
{
|
||||
mDiffuseColor = color;
|
||||
}
|
||||
|
||||
}
|
17
extern/BSAOpt/CMakeLists.txt
vendored
Normal file
17
extern/BSAOpt/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project.
|
||||
|
||||
set(BSAOPTHASH_LIBRARY "bsaopthash")
|
||||
|
||||
# Sources
|
||||
set(SOURCE_FILES
|
||||
hash.cpp
|
||||
)
|
||||
|
||||
add_library(${BSAOPTHASH_LIBRARY} STATIC ${SOURCE_FILES})
|
||||
|
||||
set(BSAOPTHASH_LIBRARIES ${BSAOPTHASH_LIBRARY})
|
||||
|
||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(BSAOPTHASH_LIBRARIES ${BSAOPTHASH_LIBRARIES} PARENT_SCOPE)
|
108
extern/BSAOpt/hash.cpp
vendored
Normal file
108
extern/BSAOpt/hash.cpp
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/* Version: MPL 1.1/LGPL 3.0
|
||||
*
|
||||
* "The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is BSAopt.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ethatron <niels@paradice-insight.us>. Portions created by The Initial
|
||||
* Developer are Copyright (C) 2011 The Initial Developer.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU Library General Public License Version 3 license (the
|
||||
* "LGPL License"), in which case the provisions of LGPL License are
|
||||
* applicable instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the LGPL License and not
|
||||
* to allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and replace
|
||||
* them with the notice and other provisions required by the LGPL License.
|
||||
* If you do not delete the provisions above, a recipient may use your
|
||||
* version of this file under either the MPL or the LGPL License."
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
#include "hash.hpp"
|
||||
|
||||
std::uint32_t GenOBHashStr(const std::string& s) {
|
||||
std::uint32_t hash = 0;
|
||||
|
||||
for (std::size_t i = 0; i < s.length(); i++) {
|
||||
hash *= 0x1003F;
|
||||
hash += (unsigned char)s[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::uint64_t GenOBHashPair(const std::string& fle, const std::string& ext) {
|
||||
std::uint64_t hash = 0;
|
||||
|
||||
if (fle.length() > 0) {
|
||||
hash = (std::uint64_t)(
|
||||
(((unsigned char)fle[fle.length() - 1]) * 0x1) +
|
||||
((fle.length() > 2 ? (unsigned char)fle[fle.length() - 2] : (unsigned char)0) * 0x100) +
|
||||
(fle.length() * 0x10000) +
|
||||
(((unsigned char)fle[0]) * 0x1000000)
|
||||
);
|
||||
|
||||
if (fle.length() > 3) {
|
||||
hash += (std::uint64_t)(GenOBHashStr(fle.substr(1, fle.length() - 3)) * 0x100000000);
|
||||
}
|
||||
}
|
||||
|
||||
if (ext.length() > 0) {
|
||||
hash += (std::uint64_t)(GenOBHashStr(ext) * 0x100000000LL);
|
||||
|
||||
unsigned char i = 0;
|
||||
if (ext == ".nif") i = 1;
|
||||
if (ext == ".kf" ) i = 2;
|
||||
if (ext == ".dds") i = 3;
|
||||
if (ext == ".wav") i = 4;
|
||||
|
||||
if (i != 0) {
|
||||
unsigned char a = (unsigned char)(((i & 0xfc ) << 5) + (unsigned char)((hash & 0xff000000) >> 24));
|
||||
unsigned char b = (unsigned char)(((i & 0xfe ) << 6) + (unsigned char)( hash & 0x000000ff) );
|
||||
unsigned char c = (unsigned char)(( i << 7) + (unsigned char)((hash & 0x0000ff00) >> 8));
|
||||
|
||||
hash -= hash & 0xFF00FFFF;
|
||||
hash += (std::uint32_t)((a << 24) + b + (c << 8));
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::uint64_t GenOBHash(const std::string& path, std::string& file) {
|
||||
std::transform(file.begin(), file.end(), file.begin(), ::tolower);
|
||||
std::replace(file.begin(), file.end(), '/', '\\');
|
||||
|
||||
std::string fle;
|
||||
std::string ext;
|
||||
|
||||
const char *_fle = file.data();
|
||||
const char *_ext = strrchr(_fle, '.');
|
||||
if (_ext) {
|
||||
ext = file.substr((0 + _ext) - _fle);
|
||||
fle = file.substr(0, ( _ext) - _fle);
|
||||
}
|
||||
else {
|
||||
ext = "";
|
||||
fle = file;
|
||||
}
|
||||
|
||||
if (path.length() && fle.length())
|
||||
return GenOBHashPair(path + "\\" + fle, ext);
|
||||
else
|
||||
return GenOBHashPair(path + fle, ext);
|
||||
}
|
42
extern/BSAOpt/hash.hpp
vendored
Normal file
42
extern/BSAOpt/hash.hpp
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/* Version: MPL 1.1/LGPL 3.0
|
||||
*
|
||||
* "The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is BSAopt.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ethatron <niels@paradice-insight.us>. Portions created by The Initial
|
||||
* Developer are Copyright (C) 2011 The Initial Developer.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU Library General Public License Version 3 license (the
|
||||
* "LGPL License"), in which case the provisions of LGPL License are
|
||||
* applicable instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the LGPL License and not
|
||||
* to allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and replace
|
||||
* them with the notice and other provisions required by the LGPL License.
|
||||
* If you do not delete the provisions above, a recipient may use your
|
||||
* version of this file under either the MPL or the LGPL License."
|
||||
*/
|
||||
#ifndef BSAOPT_HASH_H
|
||||
#define BSAOPT_HASH_H
|
||||
|
||||
#include <string>
|
||||
|
||||
std::uint32_t GenOBHashStr(const std::string& s);
|
||||
|
||||
std::uint64_t GenOBHashPair(const std::string& fle, const std::string& ext);
|
||||
|
||||
std::uint64_t GenOBHash(const std::string& path, std::string& file);
|
||||
|
||||
#endif // BSAOPT_HASH_H
|
@ -23,12 +23,7 @@ set(OENGINE_BULLET
|
||||
bullet/trace.h
|
||||
)
|
||||
|
||||
set(OENGINE_MISC
|
||||
misc/rng.cpp
|
||||
misc/rng.hpp
|
||||
)
|
||||
|
||||
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC})
|
||||
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET})
|
||||
|
||||
set(OENGINE_LIBRARY "oengine")
|
||||
set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE)
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <openengine/misc/rng.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
@ -147,7 +147,7 @@ namespace Render
|
||||
|
||||
void SelectionBuffer::getNextColour ()
|
||||
{
|
||||
Ogre::ARGB color = static_cast<Ogre::ARGB>(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits<Ogre::uint32>::max());
|
||||
Ogre::ARGB color = static_cast<Ogre::ARGB>(Misc::Rng::rollClosedProbability() * std::numeric_limits<Ogre::uint32>::max());
|
||||
|
||||
if (mCurrentColour.getAsARGB () == color)
|
||||
{
|
||||
|
@ -28,5 +28,7 @@ set_target_properties(${MYGUI_RESOURCE_PLUGIN_LIBRARY} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${MYGUI_RESOURCE_PLUGIN_LIBRARY}
|
||||
${OGRE_LIBRARIES}
|
||||
${MYGUI_LIBRARIES}
|
||||
${BSAOPTHASH_LIBRARIES} # components/bsa
|
||||
${ZLIB_LIBRARIES} # components/bsa
|
||||
components
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user