2014-01-14 04:37:06 +00:00
|
|
|
#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
|
|
|
|
#define OPENMW_MECHANICS_LEVELLEDLIST_H
|
|
|
|
|
2018-08-14 19:05:43 +00:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2016-06-17 14:07:16 +00:00
|
|
|
#include <components/misc/rng.hpp>
|
|
|
|
|
2014-01-14 04:37:06 +00:00
|
|
|
#include "../mwworld/ptr.hpp"
|
2015-02-09 14:01:49 +00:00
|
|
|
#include "../mwworld/esmstore.hpp"
|
2014-01-14 04:37:06 +00:00
|
|
|
#include "../mwworld/manualref.hpp"
|
|
|
|
#include "../mwworld/class.hpp"
|
2016-06-17 14:07:16 +00:00
|
|
|
|
2014-01-14 04:37:06 +00:00
|
|
|
#include "../mwbase/world.hpp"
|
|
|
|
#include "../mwbase/environment.hpp"
|
2016-06-17 14:07:16 +00:00
|
|
|
|
2015-08-21 09:12:39 +00:00
|
|
|
#include "creaturestats.hpp"
|
|
|
|
#include "actorutil.hpp"
|
2014-01-14 04:37:06 +00:00
|
|
|
|
|
|
|
namespace MWMechanics
|
|
|
|
{
|
|
|
|
|
|
|
|
/// @return ID of resulting item, or empty if none
|
2020-10-13 15:46:32 +00:00
|
|
|
inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Seed& seed = Misc::Rng::getSeed())
|
2014-01-14 04:37:06 +00:00
|
|
|
{
|
2015-01-31 23:26:06 +00:00
|
|
|
const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList;
|
2014-01-14 04:37:06 +00:00
|
|
|
|
2015-08-21 09:12:39 +00:00
|
|
|
const MWWorld::Ptr& player = getPlayer();
|
2014-01-14 04:37:06 +00:00
|
|
|
int playerLevel = player.getClass().getCreatureStats(player).getLevel();
|
|
|
|
|
2020-10-13 15:46:32 +00:00
|
|
|
if (Misc::Rng::roll0to99(seed) < levItem->mChanceNone)
|
2014-01-14 04:37:06 +00:00
|
|
|
return std::string();
|
|
|
|
|
|
|
|
std::vector<std::string> candidates;
|
|
|
|
int highestLevel = 0;
|
2020-07-25 11:54:49 +00:00
|
|
|
for (const auto& levelledItem : items)
|
2014-01-14 04:37:06 +00:00
|
|
|
{
|
2020-07-25 11:54:49 +00:00
|
|
|
if (levelledItem.mLevel > highestLevel && levelledItem.mLevel <= playerLevel)
|
|
|
|
highestLevel = levelledItem.mLevel;
|
2014-01-14 04:37:06 +00:00
|
|
|
}
|
|
|
|
|
2014-01-14 06:40:17 +00:00
|
|
|
// For levelled creatures, the flags are swapped. This file format just makes so much sense.
|
2015-03-06 10:19:57 +00:00
|
|
|
bool allLevels = (levItem->mFlags & ESM::ItemLevList::AllLevels) != 0;
|
2014-01-14 06:40:17 +00:00
|
|
|
if (creature)
|
|
|
|
allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
|
|
|
|
|
2014-01-14 04:37:06 +00:00
|
|
|
std::pair<int, std::string> highest = std::make_pair(-1, "");
|
2020-07-25 11:54:49 +00:00
|
|
|
for (const auto& levelledItem : items)
|
2014-01-14 04:37:06 +00:00
|
|
|
{
|
2020-07-25 11:54:49 +00:00
|
|
|
if (playerLevel >= levelledItem.mLevel
|
|
|
|
&& (allLevels || levelledItem.mLevel == highestLevel))
|
2014-01-14 04:37:06 +00:00
|
|
|
{
|
2020-07-25 11:54:49 +00:00
|
|
|
candidates.push_back(levelledItem.mId);
|
|
|
|
if (levelledItem.mLevel >= highest.first)
|
|
|
|
highest = std::make_pair(levelledItem.mLevel, levelledItem.mId);
|
2014-01-14 04:37:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (candidates.empty())
|
|
|
|
return std::string();
|
2020-10-13 15:46:32 +00:00
|
|
|
std::string item = candidates[Misc::Rng::rollDice(candidates.size(), seed)];
|
2014-01-14 04:37:06 +00:00
|
|
|
|
2014-05-22 13:29:36 +00:00
|
|
|
// Vanilla doesn't fail on nonexistent items in levelled lists
|
|
|
|
if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item)))
|
|
|
|
{
|
2018-08-14 19:05:43 +00:00
|
|
|
Log(Debug::Warning) << "Warning: ignoring nonexistent item '" << item << "' in levelled list '" << levItem->mId << "'";
|
2014-05-22 13:29:36 +00:00
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
2014-01-14 04:37:06 +00:00
|
|
|
// Is this another levelled item or a real item?
|
2014-05-22 13:29:36 +00:00
|
|
|
MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1);
|
|
|
|
if (ref.getPtr().getTypeName() != typeid(ESM::ItemLevList).name()
|
|
|
|
&& ref.getPtr().getTypeName() != typeid(ESM::CreatureLevList).name())
|
2014-01-14 04:37:06 +00:00
|
|
|
{
|
2014-05-22 13:29:36 +00:00
|
|
|
return item;
|
2014-01-14 04:37:06 +00:00
|
|
|
}
|
2014-05-22 13:29:36 +00:00
|
|
|
else
|
2014-01-14 04:37:06 +00:00
|
|
|
{
|
2014-05-22 13:29:36 +00:00
|
|
|
if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name())
|
2020-10-13 15:46:32 +00:00
|
|
|
return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false, seed);
|
2014-05-22 13:29:36 +00:00
|
|
|
else
|
2020-10-13 15:46:32 +00:00
|
|
|
return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true, seed);
|
2014-01-14 04:37:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|