1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 12:39:55 +00:00

Merge pull request #16 from cc9cii/TES4-BSA

TES4 BSA
This commit is contained in:
cc9cii 2018-10-06 19:13:38 +10:00 committed by GitHub
commit 1b56074b53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 2546 additions and 1081 deletions

View File

@ -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)

View File

@ -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

View File

@ -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"))
{

View File

@ -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);

View File

@ -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}

View File

@ -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();

View File

@ -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

View File

@ -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());
}

View File

@ -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());

View File

@ -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;

View File

@ -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}

View File

@ -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

View File

@ -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);

View File

@ -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>();

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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));

View File

@ -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);
}
}

View File

@ -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;

View File

@ -35,7 +35,7 @@ namespace MWGui
{
const ESM::GameSetting &currentSetting = *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;

View File

@ -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);

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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();

View File

@ -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()->

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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)))

View File

@ -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)

View File

@ -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));

View File

@ -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);

View File

@ -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("");

View File

@ -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"

View File

@ -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();
}
}

View File

@ -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");

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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!="")
{

View File

@ -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();

View File

@ -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))
{

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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)

View File

@ -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());

View File

@ -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)

View File

@ -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;

View File

@ -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");
}

View File

@ -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));
}

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

View File

@ -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

View File

@ -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
}

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

View 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

View File

@ -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");

View File

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

View File

@ -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] == '\\'))

View File

@ -2,8 +2,8 @@
#include <cstdlib>
#include <ctime>
namespace OEngine {
namespace Misc {
namespace Misc
{
void Rng::init()
{
@ -26,4 +26,3 @@ namespace Misc {
}
}
}

View File

@ -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

View File

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

View File

@ -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))

View File

@ -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)

View File

@ -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()

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

View File

@ -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)

View File

@ -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)
{

View File

@ -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
)