1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-30 21:32:42 +00:00
OpenMW/apps/openmw/mwmechanics/levelledlist.hpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

88 lines
3.1 KiB
C++
Raw Normal View History

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